I have an object model like below:
public class ViewModel
{
public List<Group> Groups{ get; set; }
}
public class Group
{
public string Name { get; set; }
public List<Contact> Contacts { get; set; }
}
public class Contact
{
public string Name { get; set; }
public bool IsOnline { get; set; }
}
and I'm binding the groups to an itemscontrol like this:
<ItemsControl ItemsSource="{Binding Path=Groups}"
ItemTemplate="{StaticResource GroupTemplate}" >
</ItemsControl>
and I have datatemplate for rendering them.
<DataTemplate x:Key="GroupTemplate" DataType="{x:Type Group}">
</DataTemplate>
<DataTemplate x:Key="ContactTemplate" DataType="{x:Type Contact}">
<StackPanel>
<TextBlock Text="{Binding Name}"/>
</StackPanle>
</DataTemplate>
How can I get the contacts displayed inside the items control? The contacts is a collection inside each group and my viewmodel has a collection of groups. To complicate it a bit further, I have different datatemplates for different contacts, and I should be using a datatemplateselector for choosing the appropriate contact template. Also please note, I have nothing to display in the group template, and I only need to show Contacts.
Thanks,
-Mike
Use another ItemsControl in the first template:
<DataTemplate x:Key="GroupTemplate" DataType="{x:Type my:Group}">
<ItemsControl ItemsSource="{Binding Contacts}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type my:Contact}">
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
And with a template selector:
<DataTemplate x:Key="GroupTemplate" DataType="{x:Type my:Group}">
<ItemsControl ItemsSource="{Binding Contacts}"
ItemTemplateSelector="{StaticResource yourContactItemSelector}"/>
</DataTemplate>
Related
I am trying to create a Side menu in wpf as shown in the image...
The menu is binded to an ObservableCollection (MenuList) of the class
public class MenuItemModel
{
public int MenuID { get; set; }
public string MenuName { get; set; }
public ObservableCollection<MenuItemModel> SubMenuList { get; set; }
}
The Xaml I have been using for two level,
<ItemsControl ItemsSource="{Binding MenuList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<RadioButton x:Name="Menu"
Tag="{Binding MenuID}"
GroupName="MainMenu"
Style="{StaticResource MenuButtonStyle}"
Content="{Binding MenuName}"
Height="30"/>
<ListBox x:Name="SubMenu" ItemsSource="{Binding SubMenuList}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
It works perfectly for two levels. But I am unable to figure out how to implement third level menus (like version1, version2 in the image)? Is there any way to do this in the xaml without changing Data Models?
This is the custom object:
public class FileItem
{
public string Name { get; set; }
public string Path { get; set; }
}
Collection:
public ObservableCollection<FileItem> collection { get; set; }
Combobox:
<ComboBox
Name="cbCollection"
ItemsSource="{Binding interfaces}"/>
ListBox:
<ListBox
Name="lbCollection "
ItemsSource="{Binding collection}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
So my Combobox is populated with my object collection and i want to see all its properties in my ListBox.
Currently:
I can see only the property Name.
i can see all the objects from my Combobox and not only the selected one.
If you want to see more than just the name property, you'll need to extend the data template to include the additional properties.
If you want to see the selected item's properties, then you should bind to the combo box's SelectedItem property. Actually I don't think you want a ListBox as there is only one selected item.
This should get you started:
<ContentControl Content="{Binding ElementName=cbCollection, Path=SelectedItem}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type local:FileItem}">
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
I have a View Model that is represented in the DataContext of the window.
public class SchoolViewModel:ViewModelBase
{
public ObservableCollection<SchoolClassGroup> ClassesCollection { get; set; }
....
}
public class SchooleClassGroup:ViewModelBase
{
public string ClassName {get;set;}
public string TeacherName {get;set;}
public ObservableCollection<Students> StudentCollection{ get; set; }
}
public class Student
{
public string Name {get;set;}
public int Age {get;set;}
public DateTime BirthDate {get;set;}
...
}
I want to represent a TreeView that will show me schools,class and students.
How can I do it?
Thanks!
You need to create HeirarchicalDataTemplates for each level of your object tree that has a Parent-Child relationship, plus a simple DataTemplate for the leaf node.
Your object tree should be School -> Class -> Student
class School has a
List<Class>
class Class has a
List<Student>
Then it's simple
<Window.Resources>
<HierarchicalDataTemplate ItemsSource="{Binding Classes}" DataType="{x:Type School}">
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Students}" DataType="{x:Type Class}">
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type Student}">
<TextBlock Text="{Binding Name}" />
</DataTemplate >
</Window.Resources>
<Grid>
<TreeView ItemsSource="{Binding Schools}" >
</Grid>
I am trying to create an application in which i require to display employees and their departments in the treeview kind of structure as below :
Employee1
Department
Dept1
Dept2
Employee2
Department
Dept3
Dept4
how could i do this with WPF ?
The correct way to do this is to use a HierarchicalDataTemplate. The most basic one I can imagine is the following:
<UserControl.Resources>
<HierarchicalDataTemplate
x:Key="RecursiveData" DataType="TreeViewItem" ItemsSource="{Binding Items}">
</HierarchicalDataTemplate>
</UserControl.Resources>
Which can be used in the XAML as follows:
<TreeView ItemTemplate="{StaticResource RecursiveData}" />
Of course you can customize the template at will with styles and subcomponents.
Note that the ItemSource of your TreeView needs to actually provide nested TreeViewItems where each TreeViewItem contains it's subitems in Items.
If you've structure like this:
public ObservableCollection<ChartOfAccount> ChartOfAccounts { get; set; }
public class ChartOfAccount
{
public Book Book { get; set; }
public List<LedgerHierarchy> ControlLedgers { get; set; }
}
public class LedgerHierarchy
{
public ControlLedger ControlLedger { get; set; }
public ObservableCollection<Ledger> Ledgers { get; set; }
}
you could bind directly in TreeView like this:
<TreeView ItemsSource="{Binding ChartOfAccounts}"
BorderThickness="0"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ItemContainerStyle="{StaticResource treeStyle}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding ControlLedgers}">
<TextBlock Text="{Binding Book.Name}"/>
<HierarchicalDataTemplate.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Ledgers}">
<TextBlock Text="{Binding ControlLedger.Name}"/>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
instead of creating HierarchicalDataTemplate in Control.Resource.
I have one Listbox and applied one DataTemplate like this
<ListBox>
<ListBox.ItemTemplate>
<Grid>
<TextBlock Text="{Binding Path=Name}" Grid.Row=0/>
<ComoboBox Name="test"
DisplayMemberPath="Country"
SelectedValuePath="Country_ID">
</Grid>
How will I load ItemSource to this ComboBox dynamically based on each item selected in the ListBox? Iam new to WPF... pls help with your valuable suggestions.
<ListBox>
<ListBox.ItemTemplate>
<Grid>
<TextBlock Text="{Binding Path=Name}" Grid.Row=0/>
<ComoboBox Name="test"
DataContent="{Binding RelativeSource={RelativeSource AncestorType=ListBox}}"
ItemsSource="{Binding}"
DisplayMemberPath="Country"
SelectedValuePath="Country_ID">
</Grid>
Now your combocbox is always have the same itemssource as the parent listbox.
One way to do this is to bind the ItemsSource of your ComboBox to the SelectedValue property of the ListBox. For this to work the ListBox needs to be bound to a collection of items that contains a list of items that the ComboBox will bind to.
<ListBox
x:Name="CategoryList"
ItemsSource="{Binding Path=MasterList,
RelativeSource={RelativeSource AncestorType=Window}}"
DisplayMemberPath="MasterProperty"
SelectedValuePath="Details"
/>
<ComboBox
ItemsSource="{Binding Path=SelectedValue, ElementName=CategoryList}"
DisplayMemberPath="DetailProperty"
Grid.Row="1"
/>
In this example I have created a public property in the code behind of the window that exposes a list of objects containing the Details collection.
public List<Master> MasterList { get; set; }
public class Master
{
public string MasterProperty { get; set; }
public List<Detail> Details { get; set; }
}
public class Detail
{
public string DetailProperty { get; set; }
}