Databinding between 2 listViews selecting/deselecting records - c#

I have 2 listviews, one that is prepopulated with a list of values and an empty list that should populate based on what is selected/deselected in the first view. I can get the second view to populate when a value is selected but I'm not sure how to remove an item if it's been deselected in the first view. If I do deselect a record it adds a null value to the 2nd list. I'm thinking there is a way around this with if/else statements but I'm thinking there might be a more elegant way to accomplish this.
View Model
private ObservableCollection<string> _firstList;
public ObservableCollection<string> FirstList
{
get => _firstList;
set
{
if (_firstList!= value)
{
_firstList= value;
RaisePropertyChanged(nameof(FirstList));
}
}
}
private string _selectedRecord;
public string SelectedRecord
{
get => _selectedRecord;
set
{
if (_selectedRecord!= value)
{
_selectedRecord= value;
RaisePropertyChanged(nameof(SelectedRecord));
_secondList.Add(_selectedRecord);
}
}
}
private ObservableCollection<string> _secondList=
new ObservableCollection<string>();
public ObservableCollection<string> SecondList
{
get => _secondList;
set
{
if (_secondList!= value)
{
_secondList= value;
RaisePropertyChanged(nameof(SecondList));
}
}
}
XAML -
<ListView ItemsSource="{Binding FirstList}"
SelectedItem="{Binding SelectedRecord}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"></StackPanel>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsSelected,
RelativeSource={RelativeSource
AncestorType=ListViewItem}}"/>
<TextBlock Text="{Binding}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ListView ItemsSource="{Binding SecondList}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"></StackPanel>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

Replace the string with a custom type and handle your logic of adding and removing items in the view model:
public class ListItem : INotifyPropertyChanged
{
public ListItem(string value) =>
Value = value;
public string Value { get; }
private bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set { _isSelected = value; RaisePropertyChanged(nameof(IsSelected)); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
View Model:
public ViewModel()
{
InitializeComponent();
DataContext = this;
FirstList.CollectionChanged += (s, e) =>
{
if (e.NewItems != null)
foreach (var newItem in e.NewItems.OfType<INotifyPropertyChanged>())
newItem.PropertyChanged += OnItemIsSelectedChanged;
if (e.OldItems != null)
foreach (var oldIrem in e.OldItems.OfType<INotifyPropertyChanged>())
oldIrem.PropertyChanged -= OnItemIsSelectedChanged;
};
FirstList.Add(new ListItem("a"));
FirstList.Add(new ListItem("b"));
FirstList.Add(new ListItem("c"));
}
private void OnItemIsSelectedChanged(object sender, PropertyChangedEventArgs e)
{
ListItem listItem = (ListItem)sender;
if (listItem.IsSelected)
{
if (!SecondList.Contains(listItem))
SecondList.Add(listItem);
}
else
SecondList.Remove(listItem);
}
public ObservableCollection<ListItem> FirstList { get; } =
new ObservableCollection<ListItem>();
public ObservableCollection<ListItem> SecondList { get; }
= new ObservableCollection<ListItem>();
View:
<ListView ItemsSource="{Binding FirstList}" SelectedItem="{Binding SelectedRecord}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsSelected}"/>
<TextBlock Text="{Binding Value}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ListView ItemsSource="{Binding SecondList}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Value}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This is MVVM in a nutshell.

Related

C# UWP: Access a textblock and status of check box inside a listview

Hi I have my list view as follows:
![][1]
<RelativePanel >
<ListView x:Name="StudentListView"
IsItemClickEnabled="True"
Width="1000"
ItemClick="Student_ItemClick" >
<ListView.ItemTemplate>
<DataTemplate x:Name="ABC">
<StackPanel
x:Name="ListItemPanel"
Orientation="Horizontal"
MaxWidth="500">
<TextBlock x:Name ="uName" Text="{Binding Username}"
Margin="20,0,20,8"
FontSize="24"
FontStyle="Italic"
FontWeight="SemiBold"
Foreground="DarkBlue"
/>
<CheckBox Name="AttendCheckBox"
HorizontalAlignment="Left"
Checked="AttendCheckBox_Checked"
IsChecked="False"></CheckBox>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<TextBlock Name="queryName" FontSize="20"></TextBlock>
<Button Name="finishBtn" Content="Finish" RelativePanel.Below="StudentListView" ></Button>
</RelativePanel>
I am trying to access each data item and check if checkbox is checked or not when user clicks on finish button that is on same page as listview. And I am having tough time trying to figure it out. Any hint on it would be great. Thank you
I checked your code. You did not need to use Checked event of CheckBox. Instead, you could declare a bool type property in your custom class and bind IsChecked to it and set Mode=TwoWay, then, once your checkbox's IsChecked value is changed, the source also will be updated. After that, you could filter the source to get the 'IsChecked=True' items.
According to your code snippet, I made a code sample for you reference:
<RelativePanel>
<ListView x:Name="StudentListView"
IsItemClickEnabled="True"
Width="1000" Height="500">
<ListView.ItemTemplate>
<DataTemplate x:Name="ABC">
<StackPanel
x:Name="ListItemPanel"
Orientation="Horizontal"
MaxWidth="500">
<TextBlock x:Name ="uName" Text="{Binding Username}"
Margin="20,0,20,8"
FontSize="24"
FontStyle="Italic"
FontWeight="SemiBold"
Foreground="DarkBlue"/>
<CheckBox Name="AttendCheckBox" HorizontalAlignment="Left" IsChecked="{Binding IsSelected,Mode=TwoWay}"></CheckBox>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<TextBlock Name="queryName" FontSize="20"></TextBlock>
<Button Name="finishBtn" Content="Finish" RelativePanel.Below="StudentListView" Click="{x:Bind finishBtn_Click}"></Button>
</RelativePanel>
public sealed partial class MainPage : Page
{
public ObservableCollection<Test> tests { get; set; }
public MainPage()
{
this.InitializeComponent();
tests = new ObservableCollection<Test>();
for (int i=0;i<100;i++)
{
tests.Add(new Test() {Username="name "+i });
}
StudentListView.ItemsSource = tests;
}
private void finishBtn_Click(object sender, RoutedEventArgs e)
{
var selectedStudents = tests.Where(x => x.IsSelected == true).ToList();
}
}
public class Test : INotifyPropertyChanged
{
private string _Username;
public string Username
{
get { return _Username; }
set
{
if (_Username != value)
{
_Username = value;
RaisePropertyChanged("Username");
}
}
}
private bool _IsSelected;
public bool IsSelected
{
get { return _IsSelected; }
set
{
if (_IsSelected != value)
{
_IsSelected = value;
RaisePropertyChanged("IsSelected");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string PropertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this,new PropertyChangedEventArgs(PropertyName));
}
}
}

Displaying only selected items from ListBox in new List

I'm relatively fresh to WPF and discovering XAML.
I've got one ListBox Name="EmployeeTitles" in XAML (shown below). For the purpose of demonstrating the problem DataContext = employees which is ObservableCollection<Employee>.
<ListBox Name="EmployeeTitles"
ItemsSource="{Binding}"
SelectionMode="Extended">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<ToggleButton IsChecked="{Binding IsSelected, Mode=TwoWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}">
<!--StackPanel will have more items-->
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Title}"/>
</StackPanel>
</ToggleButton>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
My "Code Behind" class snippet looks as follows:
private string _title;
public string Title
{
get { return _title; }
set
{
_title = value;
OnPropertyChanged();
}
}
private bool _isSelected;
public bool IsSelected
{
get
{
return _isSelected;
}
set
{
_isSelected = value;
OnPropertyChanged();
}
}
I would like to show the selected items in a different control. For example have a list that shows only selected items. Can I somehow mark in XAML that I only only want to display items with IsChecked="True"? I know I could have another ObservableCollection storing only selected items and updating it in "Code Behind" whenever property IsSelected changes, but that seems like an overhead and I suppose there should be a way to do it in XAML?
You can bind the other listbox with the selecteditems of the original listbox. Try the below code.
<Grid>
<StackPanel Orientation="Horizontal">
<ListBox x:Name="Emp" ItemsSource="{Binding EmpCollection}" SelectionMode="Extended">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<ToggleButton IsChecked="{Binding IsSelected, Mode=TwoWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}">
<!--StackPanel will have more items-->
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Title}"/>
</StackPanel>
</ToggleButton>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ListBox x:Name="SelectedEmp" ItemsSource="{Binding ElementName=Emp,Path=SelectedItems}" DisplayMemberPath="Title"/>
</StackPanel>
</Grid>
public partial class Window2 : Window
{
public Window2()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
}
class ViewModel
{
public ObservableCollection<Emp> EmpCollection { get; set; }
public ViewModel()
{
EmpCollection = new ObservableCollection<Emp>();
for (int i = 0; i < 10; i++)
{
EmpCollection.Add(new Emp() {Title = "Title"+i});
}
}
}
class Emp:INotifyPropertyChanged
{
private string _title;
public string Title
{
get { return _title; }
set
{
_title = value;
OnPropertyChanged();
}
}
private bool _isSelected;
public bool IsSelected
{
get
{
return _isSelected;
}
set
{
_isSelected = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

WPF Expander - Only one expander to be expanded at any time

In a WPF list view I create few WPF expanders which inside each expander I have few items. Now I want to only one of the expanders to be expanded each time...meaning all other expanders to be collopsed if one is expanded. Can you please help? Please note that the expanders are created by ItemTemplate !
XMAL :
<UserControl x:Class="DataRetrieval.Views.ParametersView"
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"
xmlns:local="clr-namespace:DataRetrieval.Views"
d:DesignWidth="400" Height=" 600" Background="White">
<UserControl.Resources>
<DataTemplate x:Key="StringDataTemplate">
<StackPanel Margin="5" >
<TextBlock Text="{Binding Name}" />
<TextBox Text="{Binding SelectedValue, UpdateSourceTrigger=PropertyChanged}" Width="290" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="DateDataTemplate">
<StackPanel Margin="5" >
<ComboBox SelectedIndex="{Binding SelectedValue, UpdateSourceTrigger=PropertyChanged}" Text="{Binding Name}" Width="290" ItemsSource="{Binding UserItems}"/>
<DatePicker SelectedDate="{Binding multitype.datetime}" Width="200"/>
</StackPanel>
</DataTemplate>
<local:ParamControlTemplateSelector x:Key="myParamTemplateSelector" />
</UserControl.Resources>
<Border BorderBrush="LightGray" BorderThickness="1,1,1,1" CornerRadius="8,8,8,8" Margin="20" Background="#FFF3F3F3">
<Grid Margin="5">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<ListView x:Name="myListView1" ItemsSource="{Binding Qtables, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" SelectedIndex="{Binding SelectedIndex}">
<ListView.ItemTemplate>
<DataTemplate>
<Expander Header="{Binding Name}" Width="320" IsExpanded="{Binding IsExpanded}" >
<StackPanel Height="600">
<TextBlock Text="{Binding Name}" />
<ListView x:Name="myListView" ItemsSource="{Binding Params, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ItemTemplateSelector="{StaticResource myParamTemplateSelector}" SelectedIndex="{Binding CurrentUser, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
</ListView>
</StackPanel>
</Expander>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ScrollViewer>
</Grid>
</Border>
</UserControl>
ViewModel
namespace DataRetrieval.ViewModel
{
class ParametersViewModel:BindableBase
{
public ParametersViewModel()
{
AParams = new WhereParams();
Qtables = new QDatatables();
for (int j = 0; j < 5;j++ )
{
for (int i = 0; i < 10; ++i)
{
int[] numbers;
numbers = new int[3] { 1, 2, 3 };
var parameter = new WhereParam { ID = i, Name = "Name " + i.ToString() };
if (i == 2 || i == 4)
{
parameter.Type = ParamTypeEnum.datetimeType;
}
AParams.Add(parameter);
}
var qtable = new QDatatable { ID=j, Name = j.ToString() + "QTable", Params = AParams};
Qtables.Add(qtable);
}
}
private WhereParam _parameter;
public WhereParam Parameter
{
get { return _parameter; }
set
{
SetProperty(ref _parameter, value);
}
}
private WhereParams _paramas;
public WhereParams AParams
{
get { return _paramas; }
set { SetProperty(ref _paramas, value); }
}
private QDatatables _qtables;
public QDatatables Qtables
{
get { return _qtables; }
set
{
SetProperty(ref _qtables, value);
}
}
}
}
This could be done by changing the Model to handle the IsExpanded
Model for QTables:
public class QDatatables : BindableBase
{
public QDatatables()
{
List.CollectionChanged += List_CollectionChanged;
}
void List_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
foreach (var item in e.NewItems)
{
var test = item as QDatatable;
test.PropertyChanged += test_PropertyChanged;
}
}
void test_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == "IsExpanded")
{
var cur = sender as QDatatable;
if (cur.IsExpanded == true)
{
foreach (var item in List)
{
if (item.Name != cur.Name && item.IsExpanded == true)
{
item.IsExpanded = false;
}
}
}
}
}
private ObservableCollection<QDatatable> _list;
public ObservableCollection<QDatatable> List
{
get { return _list ?? (_list=new ObservableCollection<QDatatable>()); }
set { SetProperty(ref _list, value); }
}
}

Binding isn't working for ListBox while using MVVM

I have a simple UserControl with a DropDown showing versions like V14, V15 etc.
I have another ListBox whose ItemSource is binded to a property in the ViewModel which depend upon the SelectedValue of the Version DropDown.
ViewModel Looks like this:
class MultiSelectEnvironmentContextControlViewModel: ViewModelBase
{
private string selectedVersion;
private DomainFacade domainFacade;
private ObservableCollection<string> environments= new ObservableCollection<string>();
public MultiSelectEnvironmentContextControlViewModel()
{
domainFacade = ((App) Application.Current).DomainFacade;
}
public IEnumerable<string> EnvironmentVersions
{
get
{
return (domainFacade.GetEnvironmentVersions().Select(v => "Version " + v));
}
}
public string SelectedVersion
{
get { return selectedVersion; }
set
{
selectedVersion = value;
RaisePropertyChanged("Environments");
}
}
public ObservableCollection<string> Environments
{
get
{
environments = (ObservableCollection<string>)(domainFacade.GetEnvironments(SelectedVersion));
return environments;
}
}
}
I am keeping track of the SelectedVersion in a property which raises PropertyChanged on Environments so that whenever SeelectedVersion changes, the Environments should update the UI.
Issue I am facing is, ehn I run the application, I see the versions being populated, but there is nothing in the ListBox.
I am setting the DataContext of the UserControl to the ViewModel in the constructor of the UserControl.
Here is how my Control.cs file looks like:
public partial class MultiSelectEnvironmentContextControl : UserControl
{
private static MultiSelectEnvironmentContextControlViewModel dataContext = new MultiSelectEnvironmentContextControlViewModel();
public MultiSelectEnvironmentContextControl()
{
InitializeComponent();
this.DataContext = dataContext;
dataContext.SelectedVersion = (string)this.ComboBoxVersions.SelectedItem;
}
private void ComboBoxVersions_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
dataContext.SelectedVersion = ((ComboBox) sender).SelectedValue.ToString();
}
}
Here is the XAML:
<ComboBox Grid.Column="0" Grid.Row="0" x:Name="ComboBoxVersions" SelectedIndex="0" Margin="10" SelectionChanged="ComboBoxVersions_OnSelectionChanged" ItemsSource="{Binding EnvironmentVersions}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<StackPanel Orientation="Horizontal" Grid.Column="1" Grid.Row="0" Margin="10">
<TextBlock VerticalAlignment="Center" Margin="0,0,10,0">Tests to be run for:</TextBlock>
<ComboBox Name="ComboBoxFileTypeSelector" ItemsSource="{Binding AvailableValidationTypes}" DisplayMemberPath="Key" SelectedValuePath="Value" SelectedIndex="0">
</ComboBox>
</StackPanel>
<ListBox x:Name="ListBoxEnvironments" Grid.Column="0" Grid.Row="1" Height="300" Grid.ColumnSpan="2" HorizontalAlignment="Stretch" Margin="10" SelectionMode="Multiple" ItemsSource="{Binding Environments}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" HorizontalAlignment="Left" Width="800" >
</WrapPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox x:Name="CheckBoxEnvironment" Content="{Binding}" IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}, Path=IsSelected}" Margin="5">
</CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
I believe this is because SelectedVersion has values like "Version 1", "Version 2", etc, but your method DomainFacade.GetEnvironments(string version) expects values like "1", "2" etc.
I would write your viewmodel like this:
public class MultiSelectEnvironmentContextControlViewModel : ViewModelBase
{
private string selectedVersion;
private DomainFacade domainFacade;
private IEnumerable<string> environments;
public MultiSelectEnvironmentContextControlViewModel()
{
domainFacade = ((App)Application.Current).DomainFacade;
EnvironmentVersions = domainFacade.GetEnvironmentVersions();
}
public IEnumerable<string> EnvironmentVersions { get; private set; }
public string SelectedVersion
{
get { return selectedVersion; }
set
{
selectedVersion = value;
RaisePropertyChanged("SelectedVersion");
Environments = domainFacade.GetEnvironments(SelectedVersion);
}
}
public IEnumerable<string> Environments
{
get { return environments; }
set
{
environments = value;
RaisePropertyChanged("Environments");
}
}
}
}
and applied to formatting of environment versions in view:
<ComboBox SelectedItem="{Binding SelectedVersion}"
ItemsSource="{Binding EnvironmentVersions}"
ItemStringFormat="Version: {0}" />

How do you bind a collection of items to a list box of checkboxes?

Sorry for the vague description, I can't think of a better way to put it.
Let's say that my ViewModel has a property as follows:
public List<MyClass> SubSystems { get; set; }
and the SubSystems class:
public class SubSystem
{
public string Name { get; set; }
public bool IsSelected { get; set; }
}
In the view, I'd like to bind the SubSystems property to, what I think would be, a list of checkboxes where the IsChecked and Name properties of the CheckBox is bound to the their respective properties, IsChecked for IsSelected and Content for Name.
I know I can make a ListBox in the XAML, but I'm not sure how I'd go about doing this using binding and a collection..
Thanks for the help!
Edit -
Here's the XAML:
<GroupBox Header="Sub-Systems" Grid.Column="0" Grid.Row="0" Margin="5">
<Grid>
<Grid.Resources>
<DataTemplate x:Key="checkBox">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsSelected}" />
<TextBlock Text="{Binding Name}" />
</StackPanel>
</DataTemplate>
</Grid.Resources>
<ListBox ItemTemplate="{StaticResource checkBox}" ItemsSource="{Binding SubSystems}" />
</Grid>
</GroupBox>
Edit #2 -
Just to clarify, all of the examples populate the box, but none of the examples are breaking on the breakpoints in the setters.
I think that instead of a ListBox, you probably want an ItemsControl. ListBoxes assume that you want to select one of the SubSystem but really, you just want to arrange the items with data templates:
<ItemsControl ItemsSource="{Binding SubSystems}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Checkbox IsChecked="{Binding IsSelected, Mode=TwoWay}" Content="{Binding Name}" />
</DataTemplate>
<ItemsControl.ItemTemplate>
</ItemsControl>
How about this:
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked={Binding IsSelected, Mode=TwoWay} /><TextBlock Text={Binding Name} />
</StackPanel>
</DataTemplate>
Do you mean something like this?
SubSystem class
public class SubSystem : INotifyPropertyChanged
{
private string mName;
private Boolean mIsSelected = false;
public SubSystem()
{
}
public SubSystem(string name, Boolean isSelected)
{
this.Name = name;
this.IsSelected = isSelected;
}
public string Name
{
get { return mName; }
set
{
if (mName != value)
{
mName = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Name"));
}
}
}
public Boolean IsSelected
{
get { return mIsSelected; }
set
{
if (mIsSelected != value)
{
mIsSelected = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("IsSelected"));
}
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
ViewModel
ObservableCollection<SubSystem> mSubSystems = new ObservableCollection<SubSystem>();
public ObservableCollection<SubSystem> SubSystems
{
get { return mSubSystems; }
set { mSubSystems = value; }
}
View
<ListBox x:Name="lstSubsystems" ItemsSource="{Binding SubSystems}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsSelected}">
<ContentPresenter Content="{Binding Name}" />
</CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Hope that helps,
Wts
Modify the ListBox.ItemTemplate to use a checkbox, and bind the CheckBox.IsChecked to SubSystem.IsSelected and CheckBox.Content to SubSystem.Name:
XAML:
<ListBox ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsSelected}" Content="{Binding Name}" Margin="5" Focusable="False" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
C#:
private void window1_Loaded(object sender, RoutedEventArgs e)
{
this.SubSystems = new List<SubSystem>();
this.SubSystems.Add(new SubSystem() { Name = "SubSystem 1", IsSelected = false });
this.SubSystems.Add(new SubSystem() { Name = "SubSystem 2", IsSelected = false });
this.SubSystems.Add(new SubSystem() { Name = "SubSystem 3", IsSelected = true });
this.SubSystems.Add(new SubSystem() { Name = "SubSystem 4", IsSelected = false });
this.SubSystems.Add(new SubSystem() { Name = "SubSystem 5", IsSelected = true });
this.DataContext = this.SubSystems;
}
And make sure you set Focusable="False" to the CheckBoxes or else your users will be able to tab into them.
EDIT:
Also from what you added you might be missing the ElementName property (if SubSystems is NOT the DataContext of your window, you need to specify where the SubSystems property is coming from with the ElementName binding property):
<ListBox ItemTemplate="{StaticResource checkBox}" ItemsSource="{Binding ElementName=window1, Path=SubSystems}" />

Categories

Resources