I have a ListBox on a WPF form. I would like to display a list of string items horizontally. I have a Grid that holds my ListBox control.
When I run the form it displays the name of the encapsulating object: ProjectName.Folder.Category instead of the string object within it.
ViewModelLocator
public CategoryViewModel CategoryViewModel
{
get
{
if (categoryviewModel == null)
{
categoryviewModel = new CategoryViewModel();
categoryviewModel.ListData.Clear();
categoryviewModel.ListData.Add(new Category { MyCategory = "new categroy1" });
categoryviewModel.ListData.Add(new Category { MyCategory = "new categroy2" });
categoryviewModel.ListData.Add(new Category { MyCategory = "new categroy3" });
categoryviewModel.ListData.Add(new Category { MyCategory = "new categroy4" });
categoryviewModel.ListData.Add(new Category { MyCategory = "new categroy5" });
categoryviewModel.ListData.Add(new Category { MyCategory = "new categroy6" });
}
return categoryviewModel;
}
}
Model
class Category
{
public String MyCategory { get; set; }
}
MainPage.xaml
<Grid>
<my:featureControl HorizontalAlignment="Left"
x:Name="featureControl1"
VerticalAlignment="Top" Height="332"
Loaded="featureControl1_Loaded" />
</Grid>
Control.xaml
<UserControl x:Class="AmebaPrototype.UI.Longlist.CategoryControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="1280">
<Grid DataContext="{Binding Source={StaticResource viewModelLocator},Path=CategoryViewModel}">
<ListBox Height="300" HorizontalAlignment="Left" Name="listBox1" VerticalAlignment="Top" Width="1280" ItemsSource="{Binding ListData}" >
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</Grid>
You need to set the DisplayMemberPath in your ListBox
This seemed to have done the trick.
<DataTemplate x:Key="ListBoxTemplate">
<TextBlock x:Name="black" Text="{Binding MyCategory}"/>
</DataTemplate>
Related
I am trying to harvest data from a ListView but am having problems harvesting the data when it is coming from a DataTemplate.
//wpf code (basic)
<ListView x:Name="anotherList">
<ListViewItem Tag="aTag" Content="A"/>
<ListViewItem Tag="bTag" Content="B"/>
</ListView>
//c# code
// In order to access data in the ListView I would do this
ListViewItem selectedItem = (ListViewItem)anotherList.SelectedItem;
String selectedContent = selectedItem.Content;
Now when I try to include a DataTemplate in there, I cannot use the same method to access the data in wpf.
//wpf code using data template
<ListView x:Name="mainList">
<ListView.ItemsSource>
// Accessing data from an inline xml table
<Binding Source="{StaticResource Book1}" XPath="Entry"/>
</ListView.ItemsSource>
<ListView.ItemTemplate>
<DataTemplate>
<ListViewItem Tag="{Binding XPath=Tag}" Content="{Binding XPath=LastName}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
//c# code
//gives null
var selectedItem = (ListViewItem)mainList.SelectedItem //....;
// throws exception
String selectedContent = selectedItem.Content;
Not sure how to proceed with the c# code since my selected item comes up as a whole string of XML content with no way to access content or tag. (i.e. it is showing up in the visual tree correctly but the ListViewItem is not behaving like a ListViewItem Object.) Is there a way to change my WPF code so that I can access the styles from the back like in the basic c# code?
Really appreciate the help and thanks for reading.
This aproach based on MVVM works for me
XAML:
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800"
d:DataContext="{d:DesignInstance local:MyViewModel}">
<Grid>
<ListView ItemsSource="{Binding Users}" SelectedItem="{Binding SelectedUser}">
<ListView.ItemTemplate>
<DataTemplate >
<Grid d:DataContext="{d:DesignInstance local:User}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding FirstName}"/>
<TextBlock Text="{Binding LastName}" Grid.Column="2"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
ViewModel:
public class MyViewModel
{
private User _selectedUser;
public MyViewModel()
{
Users = new ObservableCollection<User>
{
new User{FirstName = "User A FirstName", LastName = "User A LastName"},
new User{FirstName = "User B FirstName", LastName = "User B LastName"},
new User{FirstName = "User C FirstName", LastName = "User C LastName"}
};
}
public ObservableCollection<User> Users { get; set; }
public User SelectedUser
{
get { return _selectedUser; }
set
{
_selectedUser = value;
Debug.WriteLine(_selectedUser.LastName);
}
}
}
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
DataContext binding:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MyViewModel();
}
}
In a WPF project I have a ComboBox to select from different objects. Using an ItemsControl and it's ItemTemplateSelector I am trying to show different UI for the ComboBox selection based on a property of the object. So, in the example below we pick from person objects. In the ItemTemplateSelector we pick a different DataTemplate based on the Person's IsManager property. The trouble is it doesn't work.
I have a suspicion it might be due to the ItemsSource of the ItemsControl being bound to one item, but I am not sure. If this is the problem, what changes can I make to the code to achieve this?
XAML :
<Window x:Class="ItemsSelector.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ItemsSelector"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.Resources>
<local:Selector x:Key="selector"/>
<DataTemplate x:Key="managerTemplate">
<TextBlock Text="Manager"/>
</DataTemplate>
<DataTemplate x:Key="juniorTemplate">
<TextBlock Text="Junior"/>
</DataTemplate>
</Grid.Resources>
<ComboBox x:Name="cbo" Margin="2" Grid.Row="0" ItemsSource="{Binding .}" SelectedIndex="0">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<ItemsControl Grid.Row="1" ItemTemplateSelector="{StaticResource selector}" ItemsSource="{Binding ElementName=cbo ,Path=SelectedItem}">
</ItemsControl>
</Grid>
CODE BEHIND:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new Person[] {
new Person() { Name = "Boss", IsManager = true },
new Person() { Name = "Underling", IsManager = false }
};
}
}
PERSON:
public class Person
{
public string Name { get; set; }
public bool IsManager { get; set; }
public string Title { get; set; }
}
SELECTOR:
public class Selector : DataTemplateSelector
{
public override DataTemplate
SelectTemplate(object item, DependencyObject container)
{
FrameworkElement element = container as FrameworkElement;
if (element != null && item != null && item is Person)
{
var person = item as Person;
switch (person.IsManager)
{
case true:
return element.FindResource("managerTemplate") as DataTemplate;
case false:
return element.FindResource("juniorTemplate") as DataTemplate;
default:
break;
}
}
return null;
}
}
The ItemsSource property of an ItemsControl can only be bound to a collection that returns an IEnumerable.
You should use a ContentControl to be able to bind display the selected item of the ComboBox:
<ContentControl Grid.Row="1" ContentTemplateSelector="{StaticResource selector}"
Content="{Binding ElementName=cbo ,Path=SelectedItem}">
</ContentControl>
I think I've found the solution. I need to be using ContentTemplateSelector.
In an example WPF Project (see code below) I have a ComboBox control that uses a DataTemplate to show its bound items (an array of MyItem objects). All this works as expected. Once an item is selected on the ComboBox, it shows the full DataTemplate for the selected item. What I would like to happen instead is
When the user opens the ComboBox, it shows the full template for each bound item.
Once an item is selected (and the ComboBox closes up) for it to only show a single property of the bound item, say the Name property of the MyItem object.
Here is some example code:
XAML:
<Window x:Class="WpfApplication4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication4"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ComboBox ItemsSource="{Binding .}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Description}"/>
<TextBlock Text="{Binding Message}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
</Window>
Code behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MyItem[]
{
new MyItem() { Name = "Name1", Message="Message 1", Description = "Description 1" },
new MyItem() { Name = "Name2", Message="Message 2", Description = "Description 2" },
new MyItem() { Name = "Name3", Message="Message 3", Description = "Description 3" }
};
}
}
public class MyItem
{
public string Name { get; set; }
public string Description { get; set; }
public string Message { get; set; }
}
I have a ViewModel from which I am trying to populate a TabControl. What I want is to create tabs and all the controls in tab items from the view model.
Right now Tabs are created correctly, but the user control "CustomList" (added from Collection in the Tab class) is being added vertically in each tab and is stretched horizontally. What I want to do is to add CustomLists horizontally and it should stretch vertically.
My question is how can I add CustomList from the Collection in ViewModel in TabItem horizontally and stretched vertically?
Thanks in advance.
The code is:
MainWindow.xaml
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
xmlns:models="clr-namespace:WpfApplication1.Models"
xmlns:comps="clr-namespace:WpfApplication1.Components"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<models:ViewModel />
</Window.DataContext>
<Grid>
<TabControl ItemsSource="{Binding Tabs}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<DockPanel>
<!-- this is where user controls are added vertically -->
<ItemsControl ItemsSource="{Binding CustomLists}" DockPanel.Dock="Left" />
</DockPanel>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Grid>
</Window>
CustomList.xaml
<UserControl x:Class="WpfApplication1.Components.CustomList"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApplication1.Components"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<DockPanel LastChildFill="True">
<Label DockPanel.Dock="Top" Content="Title" x:Name="title" />
<ListView x:Name="listView" />
</DockPanel>
</UserControl>
Tab.cs
namespace WpfApplication1.Models
{
public class Tab
{
public String Header { get; set; }
public ObservableCollection<CustomList> CustomLists { get; set; } = new ObservableCollection<CustomList>();
}
}
ViewModel.cs
namespace WpfApplication1.Models
{
public class ViewModel
{
public ObservableCollection<Tab> Tabs { get; set; } = new ObservableCollection<Tab>();
public ViewModel()
{
var tab1 = new Tab();
tab1.Header = "Tab 1";
tab1.CustomLists.Add(new Components.CustomList());
tab1.CustomLists.Add(new Components.CustomList());
tab1.CustomLists.Add(new Components.CustomList());
Tabs.Add(tab1);
var tab2 = new Tab();
tab2.Header = "Tab 2";
tab2.CustomLists.Add(new Components.CustomList());
Tabs.Add(tab2);
var tab3 = new Tab();
tab3.Header = "Tab 3";
tab3.CustomLists.Add(new Components.CustomList());
tab3.CustomLists.Add(new Components.CustomList());
Tabs.Add(tab3);
}
}
}
---EDIT--- Based on Rachel's comment
MainWindow.xaml
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
xmlns:models="clr-namespace:WpfApplication1.Models"
xmlns:comps="clr-namespace:WpfApplication1.Components"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<models:ViewModel />
</Window.DataContext>
<Grid>
<TabControl ItemsSource="{Binding Tabs}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding CustomLists}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Grid>
</Window>
CustomListControl.xaml
**<UserControl x:Class="WpfApplication1.Components.CustomListControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApplication1.Components"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<DockPanel LastChildFill="True">
<Label DockPanel.Dock="Top" Content="Title" x:Name="title" />
<ListView x:Name="listView" Width="300" />
</DockPanel>
</UserControl>**
CustomList.cs
namespace WpfApplication1.Models
{
public class CustomList
{
public String Title { get; set; }
}
}
Tab.cs
namespace WpfApplication1.Models
{
public class Tab
{
public String Header { get; set; }
public ObservableCollection<CustomList> CustomLists { get; set; } = new ObservableCollection<CustomList>();
}
}
ViewModel.xaml
namespace WpfApplication1.Models
{
public class ViewModel
{
public ObservableCollection<Tab> Tabs { get; set; } = new ObservableCollection<Tab>();
public ViewModel()
{
var tab1 = new Tab();
tab1.Header = "Tab 1";
tab1.CustomLists.Add(new CustomList());
tab1.CustomLists.Add(new CustomList());
tab1.CustomLists.Add(new CustomList());
Tabs.Add(tab1);
var tab2 = new Tab();
tab2.Header = "Tab 2";
tab2.CustomLists.Add(new CustomList());
Tabs.Add(tab2);
var tab3 = new Tab();
tab3.Header = "Tab 3";
tab3.CustomLists.Add(new CustomList());
tab3.CustomLists.Add(new CustomList());
Tabs.Add(tab3);
}
}
}
I need to bind a List to a UniformGrid into a WP Window using WPF MVVM.
I had in mind to do something like this:
Into my VM:
private List<Rat> rats;
private UniformGrid uniformGrid;
public List<Rat> Rats
{
get { return rats; }
set
{
if (rats != value)
{
//update local list value
rats = value;
//create View UniformGrid
if (uniformGrid == null)
uniformGrid = new UniformGrid() { Rows=10};
else
uniformGrid.Children.Clear();
foreach(Rat rat in value)
{
StackPanel stackPanel = new StackPanel();
Ellipse ellipse = new Ellipse(){Height=20, Width=20, Stroke= Brushes.Black};
if (rat.Sex== SexEnum.Female)
ellipse.Fill= Brushes.Pink;
else
ellipse.Fill= Brushes.Blue;
stackPanel.Children.Add(ellipse );
TextBlock textBlock = new TextBlock();
textBlock.Text= rat.Name + " (" + rat.Age +")";
stackPanel.Children.Add( textBlock );
uniformGrid.Children.Add(stackPanel);
}
OnPropertyChanged("Rats");
}
}
}
The VM is correctly informed when the list needs to be refreshed into the view via an event.
So at this point I would need my View to be correctly bound to the VM. I made it this way:
<GroupBox x:Name="GB_Rats" Content="{Binding Rats}" Header="Rats" HorizontalAlignment="Left" Height="194" Margin="29,10,0,0" VerticalAlignment="Top" Width="303">
Is this the correct global approch?
Concretely, when attempting to run the code, this line fails to execute:
uniformGrid = new UniformGrid() { Rows=10};
->
An unhandled exception of type 'System.InvalidOperationException' occurred in PresentationCore.dll
Additional information: The calling thread must be STA, because many UI components require this.
This lets me think that I should not proceed this way from a MVVM point of view.
Thx for your kind assistance.
The ViewModel isn't supposed to instantiate any UI controls, this should be the View's responsibility.
So in your code you shouldn't try to create StackPanels, Ellipses etc.
Also try to use the types that already have Change notification - for instead of
List<T> use ObservableCollection<T> MSDN, i wouldn't recommend replacing a whole list when its value change.
The right way to do this in the MVVM pattern is to create a DataTemplate for the Rat like this:
ViewModel:
public class MainWindowViewModel
{
public ObservableCollection<Rat> Rats { get; set; } =
new ObservableCollection<Rat>()
{
new Rat()
{
Name = "Fred",
Age = "19",
Sex = SexEnum.Male
},
new Rat()
{
Name = "Martha",
Age = "21",
Sex = SexEnum.Female
}
};
}
Model - Rat and Sex:
public class Rat
{
public SexEnum Sex { get; set; }
public string Name { get; set; }
public string Age { get; set; }
}
public enum SexEnum
{
Female,
Male
}
As you want to present the Models value of Sex in one of two colors you should use a IValueConverter for that:
[ValueConversion(typeof(SexEnum), typeof(Brush))]
public class SexToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is SexEnum))
throw new ArgumentException("value not of type StateValue");
SexEnum sv = (SexEnum)value;
//sanity checks
if (sv == SexEnum.Female)
return Brushes.Red;
return Brushes.Blue;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
This is then used in your window:
Window:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525"
xmlns:ViewModel="WpfApplication1.VM"
xmlns:Converters ="clr-namespace:WpfApplication1.Converters"
>
<Grid>
<Grid.Resources>
<Converters:SexToColorConverter x:Key="SexToBrushConverter"></Converters:SexToColorConverter>
</Grid.Resources>
<ComboBox x:Name="comboBox" ItemsSource="{Binding Rats}" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="120">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Ellipse Width="10" Height="10" Fill="{Binding Sex, Converter={StaticResource SexToBrushConverter}}"></Ellipse>
<TextBlock Margin="5" Text="{Binding Name}"></TextBlock>
<TextBlock Margin="5" Text="{Binding Age}"></TextBlock>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
</Window>
Note the DataTemplate that is assigned to the ComboBox.ItemTemplate property and the declaration of the Converters:SexToColorConverter and its usage to change the color of the ellipse in the Fill binding.
Update 4.4.2016 16:30
Window using a GroupBox with CheckBoxes to display the list
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525"
xmlns:Converters ="clr-namespace:WpfApplication1.Converters"
xmlns:vm="clr-namespace:WpfApplication1.VM">
<Window.DataContext>
<vm:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<Grid.Resources>
<Converters:SexToColorConverter x:Key="SexToBrushConverter"></Converters:SexToColorConverter>
</Grid.Resources>
<GroupBox>
<ItemsControl ItemsSource="{Binding Rats}" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Margin="5"></CheckBox>
<Ellipse Width="10" Height="10" Fill="{Binding Sex, Converter={StaticResource SexToBrushConverter}}"></Ellipse>
<TextBlock Margin="5" Text="{Binding Name}"></TextBlock>
<TextBlock Margin="5" Text="{Binding Age}"></TextBlock>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</GroupBox>
</Grid>
</Window>
I guess the target is to also select the Rats, depending on how MVVM purist you want to be you'd add a List of RatViewModels, that have a bool IsChecked property and bind the ItemsSource to a ObservableCollection<RatViewModel> and synchronize this list with your Models List<Rat>