What's the c# code to fill these listbox with datas (strings)
I saw this on https://learn.microsoft.com/en-us/dotnet/framework/wpf/data/data-templating-overview
but there's no C# Code.
I want to have a listbox like in "Defining a Simple DataTemplate" on the link
https://learn.microsoft.com/en-us/dotnet/framework/wpf/data/data-templating-overview
Picture from listbox [1]: https://i.stack.imgur.com/K4HZS.png
<ListBox Width="400" Margin="10"
ItemsSource="{Binding Source={StaticResource myTodoList}}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=TaskName}" />
<TextBlock Text="{Binding Path=Description}"/>
<TextBlock Text="{Binding Path=Priority}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
To do this, you will need to learn about MVVM pattern.
First, you need a class TODO in the model with properties for TaskName, Description and Priority.
public class Todo
{
public string TaskName { get; set; }
public string Description { get; set; }
public int Priority { get; set; }
}
Then, you will need a class to store the collection of TODO, your "myTodoList" in the xaml :
public class TodoViewModel
{
public ObservableCollection<Todo> TodoList { get; } = new ObservableCollection<Todo>();
public TodoViewModel()
{
TodoList.Add(new Todo { TaskName = "Todo1", Description = "Todo 1 Description", Priority = 1 });
TodoList.Add(new Todo { TaskName = "Todo2", Description = "Todo 2 Description", Priority = 2 });
}
}
Then, you will need to set the datacontext in the code behind of the xaml :
public partial class MainWindow : Window
{
public MainWindow()
{
this.DataContext = new TodoViewModel();
InitializeComponent();
}
}
Finally, here is your XAML (I changed it a bit, you don't need things like "Path=") :
<ListBox Width="400" Margin="10" ItemsSource="{Binding TodoList}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding TaskName}" />
<TextBlock Text="{Binding Description}"/>
<TextBlock Text="{Binding Priority}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And it should work well :)
You should have something like this.
MainWindow.xaml.cs:
public List<ToDo> ToDoList {get; set;}
public MainWindow()
{
InitializeComponent();
DataContext=this;
ToDoList= new List<ToDo>()
{
new ToDo{TaskName="Task1",Description="First Task"},
new ToDo{TaskName="Task2",Description="Second Task"}
};
}
ToDo.cs:
public class ToDo
{
public string TaskName {get; set;}
public string Description {get; set;}
}
Modify your Binding expression to:
<ListBox Width="400" Margin="10"
ItemsSource="{Binding ToDoList}">
Related
I am trying to create a <ListView> with XAML. The list is supposed to show the contents of a list of the class Task.
taskView.ItemsSource = company.tasks;
The version of XAML I am using is the one contemplated on MAUI therefore most tutorials show elements than are not included in the XAML version used.
I tried to do it as following:
<ListView x:Name="taskView"
Margin="120,0,0,60"
ItemsSource="{Binding tasks}"
ItemSelected="taskView_SelectionChanged">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding name}"/>
<TextCell Text="{Binding status}"/>
<TextCell Text="{Binding dedaline}"/>
<TextCell Text="{Binding description}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
But it did not work. It would neither open the app nor throw an exception.
If I leave only one <TextCell>, it opens and shows (only the name). How can I show more details?
Here is the class Task:
public class Task
{
public Task(string name, List<string> departments, Status status, DateOnly deadline, string description)
{
this.name = name;
this.departments = departments;
this.status = status;
this.deadline = deadline;
this.description = description;
}
public string name { get; private set; }
public List<string> departments { get; private set; } = new List<string>();
public Status status { get; private set; }
public DateOnly deadline { get; private set; }
public Employee? author { get; set; }
public string description { get; private set; }
public List<Employee> employees { get; private set; } = new List<Employee>();
}
I am fairly new to XAML and would candidly appreciate some help.
Thank you.
First an irrelevant thing. The class "Task" may cause you problem because you already have System.Threading.Task in .net.
You shouldn't bind the ListView (or CollectionView) to a source twice for the same purpose as #Jason said.
XAML FILE
<ContentPage
x:Class="MauiApp.MainPage"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:models="clr-namespace:MauiApp.Models"
xmlns:views="clr-namespace:MauiApp.Views"
x:DataType="views:MainPage">
<CollectionView
ItemsSource="{Binding Tasks}">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="models:Task">
<VerticalStackLayout Margin="15">
<Entry Text="{Binding name}" />
<Entry Text="{Binding status}" />
<Entry Text="{Binding deadline}" />
<Entry Text="{Binding description}" />
</VerticalStackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</ContentPage>
Check the XML namespaces (xmlns). I assumed you have your Task model inside "Models" folder and your views inside "Views" folder. You need this import because your content page's datatype is binded with MainPage, but your CollectionView is binded with Task class.
Inside DataTemplate you can have only 1 item. So you should choose a container item, like VerticalStackLayout in this answer.
CLASS FILE
public partial class MainPage : ContentPage
{
public ObservableCollection<Task> Tasks { get; set; } = new ObservableCollection<Task>();
public MainPage()
{
InitializeComponent();
BindingContext = this;
Tasks.Add(new Task("task 1", new List<string>() { "dep1", "dep2" }, "status 1", DateOnly.MinValue, "description 1"));
Tasks.Add(new Task("task 2", new List<string>() { "dep3", "dep4" }, "status 2", DateOnly.MinValue, "description 2"));
}
}
In your class you could use ObservableCollection and you must bind Context with BindingContext = this;
If you are using MVVM, than you can bind that to your ViewModel.
This should work as expected, although you may need to class OnPropertyChanged if needed.
a ListView's DataTemplate can only contains a single child element. If you want to have multiple data elements, use a ViewCell instead of a TextCell and build your own custom layout
<ViewCell>
<StackLayout BackgroundColor="#eee"
Orientation="Vertical">
<StackLayout Orientation="Horizontal">
<Image Source="{Binding image}" />
<Label Text="{Binding title}"
TextColor="#f35e20" />
<Label Text="{Binding subtitle}" HorizontalOptions="EndAndExpand"
TextColor="#503026" />
</StackLayout>
</StackLayout>
</ViewCell>
I want to ListView with expander including some of information. So, I made this code. I'm not sure binding expander like that is correct. I just try to Binding like ListViewItem, But when I try to expander is not work at all. Here is my code.
XAML :
<Grid Grid.Row="2">
<ListView x:Name="lv">
<ListView.Template>
<ControlTemplate>
<HeaderedItemsControl>
<ItemsPresenter/>
</HeaderedItemsControl>
</ControlTemplate>
</ListView.Template>
<ListView.ItemTemplate>
<DataTemplate DataType="{x:Type local:LogBase}">
<Expander Grid.Column="0" HorizontalAlignment="Center">
<Expander.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal"> <!-- why this code is not wokring...? -->
<TextBlock Text="{Binding No}"/>
<TextBlock Text="{Binding Timestamp}"/>
<TextBlock Text="{Binding Type}"/>
</StackPanel>
</DataTemplate>
</Expander.HeaderTemplate>
</Expander>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
code behind :
public partial class MainWindow : Window
{
public List<LogBase> logs { get; set; }
public MainWindow()
{
InitializeComponent();
logs = new List<LogBase>();
logs.Add(new LogBase()
{
No = "1",
Timestamp = "123456789",
Type = "Tcp"
});
logs.Add(new LogBase()
{
No = "2",
Timestamp = "123456789",
Type = "Tcp"
});
logs.Add(new LogBase()
{
No = "3",
Timestamp = "123456789",
Type = "Tcp"
});
lv.ItemsSource = logs;
DataContext = this;
}
}
public class LogBase
{
public string No { get; set; }
public string Timestamp { get; set; }
public string Type { get; set; }
}
for better understanding I captured what I want to
Now my program's situation
If you have any of opinions please comment for me!
You also need to bind the header to set the DataContext of the HeaderTemplate correct. This is done by Header="{Binding HeaderSource}". In your case just use Header="{Binding}" to bind directly to the item:
<Expander Header="{Binding}>
After that your code works perfectly.
I have created a treeview in my xaml.
<TreeView Name="exportTreeView" ItemsSource="{Binding}" Width="350" >
<TreeView.Resources>
<DataTemplate x:Key="layersTemplate">
<StackPanel Orientation="Horizontal" Margin="10,0,0,0">
<CheckBox Foreground="White" IsChecked="{Binding IsToBeExported}" VerticalAlignment="Center" />
<Label Style="{StaticResource baseStyle}" Content="{Binding Path=Name}" VerticalAlignment="Center" />
</StackPanel>
</DataTemplate>
<HierarchicalDataTemplate x:Key="objectTemplate" ItemsSource="{Binding Path=LayersList}" ItemTemplate="{StaticResource ResourceKey=layersTemplate}">
<StackPanel Orientation="Horizontal" Height="15" Margin="10,0,0,0">
<CheckBox Foreground="White" IsChecked="{Binding IsToBeExported}" VerticalAlignment="Center" />
<Label Style="{StaticResource baseStyle}" Content="{Binding Path=Name}" VerticalAlignment="Center" />
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.Resources>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=ObjectList}" ItemTemplate="{StaticResource ResourceKey=objectTemplate}">
<StackPanel Orientation="Horizontal" Margin="10,0,0,0">
<CheckBox Foreground="White" IsChecked="{Binding IsToBeExported}" VerticalAlignment="Center" />
<Label Style="{StaticResource baseStyle}" Content="{Binding Path=Name}" VerticalAlignment="Center" />
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
The tree structure is like below. Each Parent can have any number of children & each Child can have any number of Grandchildren. Multiple selection is allowed too.
Parent
-Child
--Grandchild
I have checkboxes for all levels. I am not getting how to access its nodes individually and also how to use the tree data.
In my VM class, I set the datacontext of this TreeView to a 3 class list like below:
public class MProject
{
public string Name { get; set; }
public bool IsToBeExported { get; set; }
public List<MWorkObject> ObjectList { get; set; }
}
public class MWorkObject
{
public string Name { get; set; }
public bool IsToBeExported { get; set; }
public List<MLayer> LayersList { get; set; }
}
public class MLayer
{
public string Name { get; set; }
public bool IsToBeExported { get; set; }
}
My requirement is:
Selecting the parent should select all its child and grandchild.
How to identify in the code which item is selected ? Need it to do further processing.
Please help.
You need to implement INotifyPropertyChanged for your classes. Then
in setter of IsToBeExported in MProject handle all children (set
IsToBeExported to what you need). The binding makes the change
visible in tree
if IsToBeExported set to true, then it is selected
Example:
public class ViewBase :INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string info)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(info));
}
}
public class MProject : ViewBase
{
public string Name
{
get
{
return _name;
}
set
{
if (value != _name)
{
_name = value;
NotifyPropertyChanged(nameof(Name));
}
}
}
private string _name;
...
}
I am pretty new to WPF. I am trying to create controls dynamically in MVVM but controls are not rendered on view. I want some number of label and textbox to be created on view.
Below is my code:
Model Code
public class MyModel
{
public string KeyName
{
get;
set;
}
public string KeyValue
{
get;
set;
}
}
ModelView Code
public class MyViewModel
{
private ObservableCollection<MyModel> propertiesList = new ObservableCollection<MyModel>();
public CustomWriterViewModel()
{
GetMyProperties()
}
public ObservableCollection<MyModel> Properties
{
get { return propertiesList; }
}
private void GetMyProperties()
{
MyModel m = new MyModel();
m.KeyName = "Test Key";
m.KeyValue = "Test Value";
MyModel.Add(m);
}
}
View Code(Which is user control)
<Grid>
<ItemsControl ItemsSource="{Binding Properties}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type cw:MyModel}">
<StackPanel Orientation="Horizontal">
<Label Margin="10" Content="{Binding Properties.KeyName}"></Label>
<TextBox Margin="10" Text="{Binding Properties.KeyValue}" Width="250"></TextBox>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
When view renders, I can only see empty textbox. I cannot understand what is wrong..?
As per my comment:
The DataTemplate receives an individual item as its DataContext, therefore you only need to include item level property names within your binding paths like:
<DataTemplate DataType="{x:Type cw:MyModel}">
<StackPanel Orientation="Horizontal">
<Label Margin="10" Content="{Binding KeyName}"></Label>
<TextBox Margin="10" Text="{Binding KeyValue}" Width="250"></TextBox>
</StackPanel>
</DataTemplate>
example
class abc
{
public ObservableCollection<string> Data { get; set; }
//data will be initialized in some functions
}
and wpf application
namespace WpfApplication
{
public partial class MainWindow : Window
{
[Import(typeof(GateManager))]
public abc _abc { get; set; }
public MainWindow()
{
InitializeComponent();
}
}
public void OnImportsSatisfied()
{
var binding = new Binding
{
Source = _abc,
Path = new PropertyPath("Data")
};
databox.SetBinding(ItemsControl.SourceProperty, binding);
//databox is name of the ItemControl like //<ItemsControl x:Name="databox" ScrollViewer.VerticalScrollBarVisibility="Auto">
// <ItemsControl.ItemTemplate>
// <DataTemplate>
// <StackPanel Orientation="Horizontal">
// <TextBlock Text="{Binding}" />
// </StackPanel>
// </DataTemplate>
//</ItemsControl.ItemTemplate>
//</ItemsControl> }
}
}
Im trying to do like this but this is not working
Add DataContext also
<Window.DataContext>
<ViewModel:ManageUserViewModel/>
</Window.DataContext>
in cs file :
private ObservableCollection<UserType> _listUserTypes = new ObservableCollection<UserType>();
public ObservableCollection<UserType> UserTypes
{
set
{
_listUserTypes = value;
}
get
{
return _listUserTypes;
}
}
In Xaml:
<ItemsControl ItemsSource="{Binding Path=UserTypes, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
public List<string> Data { get; set; }
in XAML,
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
You want to set the ItemSource to the instance of an ObservableCollection you created in the constructor:
YourItemsControL.ItemsSource = Data ;