You're making a lot of work for yourself. You need to simplify your code. Here is an example for you:
1. First, sperate the
INotifyPropertyChanged
into a reusable base class:
public abstract class ObservableBase : INotifyPropertyChanged
{
public void Set<TValue>(ref TValue field, TValue newValue,
[CallerMemberName] string propertyName = "")
{
if (EqualityComparer<TValue>.Default.Equals(field, default(TValue))
|| !field.Equals(newValue))
{
field = newValue;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
2. Next, lets encapsulate ueach country into its own model:
public class CountryModel : ObservableBase
{
private bool isChecked;
public bool IsChecked
{
get { return isChecked; }
set { Set(ref isChecked, value); }
}
private string name;
public string Name
{
get { return name; }
set { Set(ref name, value); }
}
}
3. Now lets include the collection of countries into our ViewModel:
public class MainViewModel : ObservableBase
{
public ObservableCollection<CountryModel> Countries { get; set; } = new ObservableCollection<CountryModel>
{
new CountryModel { Name = "India", IsChecked = true },
new CountryModel { Name = "US" },
new CountryModel { Name = "UK" },
new CountryModel { Name = "China" }
};
}
4. Lastly, time to do the UI: Show the list of selectable countries to the User. I have also added a list of selected countries that reflects the changes made by the user:
4a. XAML Page:
<Window
x:Class="MultiSelectCheckList.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
mc:Ignorable="d"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:clr="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:MultiSelectCheckList"
Title="CodeProject - MultiSelect CheckboxList"
Height="350" Width="525" WindowStartupLocation="CenterScreen">
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Window.Resources>
<CollectionViewSource x:Key="SelectedCountries" Source="{Binding Countries}"
IsLiveFilteringRequested="True"
Filter="CollectionViewSource_Filter">
<CollectionViewSource.LiveFilteringProperties>
<clr:String>IsChecked</clr:String>
</CollectionViewSource.LiveFilteringProperties>
</CollectionViewSource>
</Window.Resources>
<Grid Margin="20">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ItemsControl x:Name="Selection" ItemsSource="{Binding Countries}"
BorderThickness="1" BorderBrush="Silver">
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type local:CountryModel}">
<CheckBox Content="{Binding Name}"
IsChecked="{Binding IsChecked, Mode=TwoWay}"
Margin="10"/>
</DataTemplate>
</ItemsControl.Resources>
</ItemsControl>
<ListBox Grid.Column="1" Margin="10 0 0 0"
ItemsSource="{Binding Source={StaticResource SelectedCountries}}">
<ListBox.Resources>
<DataTemplate DataType="{x:Type local:CountryModel}">
<TextBlock Text="{Binding Name}" Margin="10"/>
</DataTemplate>
</ListBox.Resources>
</ListBox>
</Grid>
</Window>
4b. Code-behind for the CollectionViewSource filter:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void CollectionViewSource_Filter(object sender, FilterEventArgs e)
{
e.Accepted = (e.Item as CountryModel).IsChecked;
}
}
Now, the list of countries is easily expandable without any changes to the XAML code.