I have a ListView in which I added a column with a checkBox like so:
<ListView.View>
<GridView>
<GridViewColumn Width="60" Header="{x:Static properties:Resources.HistoryViewer_checkBoxRelaunch}" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox Name="checkBoxRelaunch" Checked="checkBoxRelaunch_Checked" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
the thing is that I need to be aware of which checkboxes were cheked by users, but I can't seem to get to that.
Bear in mind that the ListView is bound to a CollectionViewSource
thanks in advance.
The practice is to feed your collection with a class that
contains a property that will be linked to your check box.
inherits INotifyPropertyChanged
For example, what I use in most of my projects
In XAML
<ListBox Grid.Row="1" Margin="5" MinHeight="200" Name="checkedListBoxControlFund" ScrollViewer.VerticalScrollBarVisibility="Auto" >
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsChecked}" Content="{Binding Label}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In your code
public class CheckBoxItemForWPF : IComparable<CheckBoxItemForWPF>, INotifyPropertyChanged
{
public object Item { get; set; }
private string _label;
public string Label
{
get { return _label; }
set { _label = value; OnPropertyChanged("Label"); }
}
private bool _isChecked;
public bool IsChecked
{
get { return _isChecked; }
set { _isChecked = value; OnPropertyChanged("IsChecked"); }
}
private SolidColorBrush _couleur;
public SolidColorBrush Couleur
{
get { return _couleur; }
set { _couleur = value; OnPropertyChanged("Couleur"); }
}
public CheckBoxItemForWPF(object item)
{
this.Item = item;
this.Label = item.ToString();
this.IsChecked = true;
this.Couleur = new SolidColorBrush(Colors.White);
}
public CheckBoxItemForWPF(object item, string label)
{
this.Item = item;
this.Label = label;
this.IsChecked = true;
this.Couleur = new SolidColorBrush(Colors.White);
}
public CheckBoxItemForWPF(string label, bool IsChecked)
{
this.Label = label;
this.IsChecked = IsChecked;
this.Couleur = new SolidColorBrush(Colors.White);
}
public CheckBoxItemForWPF(object item, string label, bool IsChecked)
{
this.Item = item;
this.Label = label;
this.IsChecked = IsChecked;
this.Couleur = new SolidColorBrush(Colors.White);
}
public CheckBoxItemForWPF(object item, string label, bool IsChecked, SolidColorBrush Couleur)
{
this.Item = item;
this.Label = label;
this.IsChecked = IsChecked;
this.Couleur = Couleur;
}
public override bool Equals(object obj)
{
// If parameter is null return false.
if (obj == null)
{
return false;
}
// If parameter cannot be cast to Point return false.
CheckBoxItemForWPF p = obj as CheckBoxItemForWPF;
if ((System.Object)p == null)
{
return false;
}
return Item.Equals(p.Item);
}
public override int GetHashCode()
{
return Item.GetHashCode();
}
public override string ToString()
{
return Label;
}
public int CompareTo(CheckBoxItemForWPF other)
{
return this.Label.CompareTo(other.Label);
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string info)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(info));
}
}
}
In your code, you can retrieve checked elements with a LINQ request or a foreach
source : BindingList<CheckBoxItemForWPF> list
foreach (CheckBoxItemForWPF i in list)
if (i.IsChecked)
...
You can find the answer at MSDN How to: Create ListViewItems with a CheckBox
The trick is to bind the IsChecked property of the Checkbox to the IsSelected property of the ListViewItem
Related
I'm trying to bind checkbox ischecked value. but whenever I click multiple checkbox, only last item is get selected.
This is my xaml.
<ListBox x:Name="EntryBox" ItemsSource="{Binding SourceCollection}"
SelectedItem="{Binding SelectedCheckbox}" SelectionMode="Multiple"
Grid.Column="0" Grid.Row="0" >
<ListBox.ItemTemplate>
<DataTemplate>
<ListBoxItem IsSelected="{Binding Selected}">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding Selected}"/>
</StackPanel>
</ListBoxItem>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
My viewmodel
public class MytViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private ObservableCollection<Item> _socketEntryCollection;
public MyViewModel()
{
_socketEntryCollection = new ObservableCollection<Item>();
}
private ListCollectionView _sourceCollection;
public ListCollectionView SourceCollection
{
get { return _sourceCollection; }
set
{
_sourceCollection = value;
NotifyPropertyChanged(nameof(SourceCollection));
}
}
private Item _selectedCheckbox;
public Item SelectedCheckbox
{
get
{
return _selectedCheckbox;
}
set
{
_selectedCheckbox = value;
NotifyPropertyChanged(nameof(SelectedCheckbox));
}
}
public class Item : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool _selected;
public Item()
{
_selected = false;
}
public bool Selected
{
get { return _selected; }
set
{
if(_selected != value)
{
_selected = value;
NotifyPropertyChanged(nameof(Selected));
}
}
}
private void NotifyPropertyChanged(string Obj)
{
if (PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(Obj));
}
}
In my code behind,
private MyViewModel _BVM;
public BulkTest()
{
InitializeComponent();
_BVM = new MyViewModel();
}
foreach (MyViewModel.Item i in _BVM.SourceCollection)
{
if (i.Selected)
{
}
}
When I try to retrieve selected items, it only gives me only the last item I checked even though I checked multiple.
I would like to get every item that I checked.
How can I do that?
I am displaying data with a structure similar to the folder structure on a disc and I want to filter it. If an item is unselected all items under that one are unselected too. If an item low in the tree is selected, all parents to up to the root are selected. The selection shall result in reloading and displaying the data matching the selected items.
For this I have created a TreeFilter class which is displayed a standard WPF TreeView.
When the selection is changed I want to build a list with selected items in the tree (I will extend the TreeFilter class with an additional property for that)
As the combination of items is fixed I created a static class which returns predefined sets of filters (trees).
I even managed to put the whole thing into a UserControl (I am still relatively new to c# and WPF) to be able to reuse it as I will need it in different parts of the solution. The control has a dependency property to bind the filter tree.
I don’t want to use code behind, as everything is MVVM
My problem is the following: How do I even notice, when an item is selected so I can reflect that change in updating the data? When any of those checkboxes is changed (on/off) I want to update the data-view
Thank you very much for your patience and support!
This is my code:
The TreeFilter class
public class DTTreeFilter : INotifyPropertyChanged
{
public string Caption { get; set; }
public string Description { get; set; }
bool isEnabled;
public bool IsEnabled
{
get => isEnabled;
set
{
if (value != this.isEnabled)
{
this.isEnabled = value;
if (this.isEnabled == false)
{
foreach (var child in children)
{
child.IsEnabled = false;
}
}
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsEnabled)));
}
}
}
private bool isExpanded;
public bool IsExpanded
{
get { return isExpanded; }
set
{
if (value != isExpanded)
{
isExpanded = value;
NotifyPropertyChanged(nameof(IsExpanded));
}
}
}
private bool isSelected;
public bool IsSelected
{
get { return isSelected; }
set
{
if (value != isSelected)
{
isSelected = value;
NotifyPropertyChanged(nameof(IsSelected));
}
}
}
private bool isFilterSelected;
public bool IsFilterSelected
{
get { return isFilterSelected; }
set
{
if (value != isFilterSelected)
{
isFilterSelected = value;
if (this.isFilterSelected == false)
{
foreach (var child in children)
{
child.IsFilterSelected = false;
}
}
// Filter ein -> alle Eltern einschalten
if (this.isFilterSelected == true)
{
if (this.Parent != null)
this.Parent.IsFilterSelected = true;
}
NotifyPropertyChanged(nameof(IsFilterSelected));
}
}
}
public DTTreeFilter Parent { get; set; }
ObservableCollection<DTTreeFilter> children;
public ObservableCollection<DTTreeFilter> Children
{
get => children;
set => children = value;
}
public static DTTreeFilter Create(string Caption, string Description, DTTreeFilter Parent = null)
{
return new DTTreeFilter(Caption, Description, Parent);
}
public DTTreeFilter(string Caption, string Description, DTTreeFilter Parent = null)
{
children = new ObservableCollection<DTTreeFilter>();
this.Caption = Caption;
this.Description = Description;
this.IsEnabled = true;
if (Parent != null)
this.Parent = Parent;
}
public void AddChild(DTTreeFilter child)
{
child.Parent = this;
children.Add(child);
this.IsExpanded = true;
}
public override string ToString()
{
return $"ToString {this.Caption }";
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
The TreeView
<TreeView
x:Name="trFilter"
ItemsSource="{Binding FilterList}" >
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:DTTreeFilter}"
ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsFilterSelected}"
IsEnabled="{Binding IsEnabled}"
VerticalContentAlignment="Center"/>
<TextBlock Text="{Binding Caption}"
VerticalAlignment="Center"
FontWeight="DemiBold"
FontSize="14"
/>
<TextBlock Text=" " />
<TextBlock Text="{Binding Description}"
VerticalAlignment="Center"
Width="250"
FontSize="11"/>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.Resources>
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected}" />
<Setter Property="IsExpanded" Value="{Binding IsExpanded}" />
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
The prepared Filterset
public static DTTreeFilter GetFilterSetA()
{
DTTreeFilter rootItem = DTTreeFilter.Create("Root Item", "this is the root item");
DTTreeFilter childItemA = DTTreeFilter.Create("Child A", "this is child A");
DTTreeFilter childItemB = DTTreeFilter.Create("Child B", "this is child B");
rootItem.AddChild(childItemA);
rootItem.AddChild(childItemB);
DTTreeFilter childItemA1 = DTTreeFilter.Create("Child A1", "this is child A1");
DTTreeFilter childItemA2 = DTTreeFilter.Create("Child A1", "this is child A2");
childItemA.AddChild(childItemA1);
childItemA.AddChild(childItemA2);
return rootItem;
}
The ViewModel
public class TreeFilterTestViewModel
{
public virtual ObservableCollection<DTTreeFilter> AllFilters { get; set; } = new ObservableCollection<DTTreeFilter>();
public TreeFilterTestViewModel()
{
AllFilters.Add( DTSystemFilter.GetFilterSetA() );
}
resulting in
enter image description here
I am trying to bind SelectedIndex of ListBox inside Pivot. Headers, Items are bind correctly, however, the ListBox SelectedIndex is somehow not working.
XAML
<Page.DataContext>
<local:ChapterMenuViewModel/>
</Page.DataContext>
<Pivot x:Name="pvMain" TitleTemplate="{StaticResource PivotTitleTemplate}"
HeaderTemplate="{StaticResource PivotHeaderTemplate}"
ItemsSource="{Binding ChapterMenuHeader}" SelectionChanged="pvMain_SelectionChanged">
<Pivot.ItemTemplate>
<DataTemplate>
<Grid Grid.Row="1" Grid.Column="0">
<ListBox FlowDirection="RightToLeft" FontFamily="./Fonts/ScheherazadeRegOT.ttf#Scheherazade"
x:Name="lsbChapter" ItemTemplate="{StaticResource ChapterItemTemplate}"
SelectedIndex="{Binding SelectedChapterIndex}"
ItemsSource="{Binding Chapters}">
</ListBox>
</Grid>
</DataTemplate>
</Pivot.ItemTemplate>
</Pivot>
MVVM
public class ChapterMenuViewModel : INotifyPropertyChanged
{
ObservableCollection<ChapterMenusHeader> _chapterMenuHeader;
DataSource ds = null;
public ChapterMenuViewModel()
{
ChapterMenuHeader = new ObservableCollection<ChapterMenusHeader>();
ds = new DataSource();
List<JuzDetail> allJuz = DataSource.GetAllJuz;
ChapterMenuHeader.Add(new ChapterMenusHeader() { Header = "chapter", Chapters = DataSource.GetAllChapter, Juzs = allJuz });
ChapterMenuHeader.Add(new ChapterMenusHeader() { Header = "location", Chapters = DataSource.GetAllChapterSortedByChapterType, Juzs = allJuz });
ChapterMenuHeader.Add(new ChapterMenusHeader() { Header = "order", Chapters = DataSource.GetAllChapterSortedByOrder, Juzs = allJuz });
ChapterMenuHeader.Add(new ChapterMenusHeader() { Header = "size", Chapters = DataSource.GetAllChapterSortedBySize, Juzs = allJuz });
ChapterMenuHeader.Add(new ChapterMenusHeader() { Header = "arabic name", Chapters = DataSource.GetAllChapterSortedByArabicAlphabet, Juzs = allJuz });
ChapterMenuHeader.Add(new ChapterMenusHeader() { Header = "english name", Chapters = DataSource.GetAllChapterSortedByEnglishAlphabet, Juzs = allJuz });
}
public ObservableCollection<ChapterMenusHeader> ChapterMenuHeader
{
get { return _chapterMenuHeader; }
set
{
if (_chapterMenuHeader != value)
{
_chapterMenuHeader = value;
OnPropertyChanged("ChapterMenuHeader");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public class ChapterMenusHeader : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public ChapterMenusHeader()
{
SelectedChapterIndex = App.Recent.ChapterID;
}
string _header;
public string Header
{
get { return _header; }
set
{
if (_header != value)
{
_header = value;
OnPropertyChanged("Header");
}
}
}
List<Chapter> _allChapters;
public List<Chapter> Chapters
{
get { return _allChapters; }
set
{
if (_allChapters != value)
{
_allChapters = value;
OnPropertyChanged("Chapters");
}
}
}
int _selectedChapterIndex;
public int SelectedChapterIndex
{
get { return _selectedChapterIndex; }
set
{
_selectedChapterIndex = value;
OnPropertyChanged("SelectedChapterIndex");
}
}
List<JuzDetail> allJuz;
public List<JuzDetail> Juzs
{
get { return allJuz; }
set
{
if (allJuz != value)
{
allJuz = value;
OnPropertyChanged("Juzs");
}
}
}
}
Scrolling Section
private void lsbChapter_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListBox lsb = sender as ListBox;
if (lsb.SelectedIndex != -1)
scrollIntoSelectedItem(lsb, lsb.SelectedIndex);
}
void scrollIntoSelectedItem(ListBox lsb, int index)
{
lsb.SelectionChanged -= lsbChapter_SelectionChanged;
lsb.SelectedIndex = lsb.Items.Count - 1;
lsb.UpdateLayout();
lsb.ScrollIntoView(lsb.SelectedIndex);
lsb.SelectedIndex = index;
lsb.UpdateLayout();
lsb.ScrollIntoView(index);
lsb.SelectionChanged += lsbChapter_SelectionChanged;
}
This is only portion of the ViewModel class where I am binding the SelectedIndex of ListBox.
The ListBox items are bind correctly, however, the SelectedIndex is not working.
How to set and scroll the SelectedIndex of ListBox in Pivot?
Thanks!
So turns out the issue is at this line -
SelectedIndex="{Binding SelectedChapterIndex}" ItemsSource="{Binding Chapters}"
You need to move the ItemsSource binding in front of the SelectedIndex one -
ItemsSource="{Binding Chapters}" SelectedIndex="{Binding SelectedChapterIndex}"
The reason? I suspect that it's because of the instantiation sequence of the two values. When the SelectedIndex is placed in front of the ItemsSource in xaml and assigned with a value in the constructor, the ItemsSource is still null, so nothing will be selected.
Now, to scroll to a particular item, you need to call the ScrollIntoView method on the ListBox. In your case, it should be
lsbChapter.ScrollIntoView(Chapters[SelectedChapterIndex]);
My code generates panels on function call defined in .cs file. There is ItemControl used in code to generates these Panels . Each Panel has it's Textbox , Slider and Combobox.
Each Panel's Slider and Combobox is playing with TextBox.Text Like:
Slider to increase Textbox.Text Font Size.
Combobox to Select alignment of TextBox.Text.
I want to replace Combobox with Button with Content Left. So as i click on Button it's Content must change to Right and similarly from Right to Left., to make changes to Alignment.
Can anyone solve my problem? Here Code is:
XAML FILE:
<ItemsControl x:Name="lstItemsClassM" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<ComboBox x:Name="cboOccupation" IsEditable="False" HorizontalAlignment="Left"
Text="{Binding Path=Alignment, Mode=TwoWay}"
Margin="4" Width="140">
<ComboBoxItem>Right</ComboBoxItem>
<ComboBoxItem>Left</ComboBoxItem>
</ComboBox>
<Button Content="{Binding Alignment, Mode=TwoWay}" Click="Button_Click" Tag="{Binding PKId}" SourceUpdated="Button_SourceUpdated" />
<TextBox x:Name="txtText" Width="300" Height="100" Text="{Binding Text;, Mode=TwoWay}" FontSize="{Binding FontSize, Mode=OneWay}" TextAlignment="{Binding Alignment, Mode=OneWay}" />
<Slider Minimum="10" Maximum="30" Value="{Binding FontSize, Mode=TwoWay}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
.cs File
public partial class Window2 : Window
{
protected ObservableCollection<ClassM> texts = new ObservableCollection<ClassM>();
int dv;
public Window2()
{
InitializeComponent();
dv=1;
texts.Add(new ClassM() { PKId=dv, Text = "Test 1" });
dv=2;
texts.Add(new ClassM() { PKId=dv, Text = "Test 2" });
lstItemsClassM.ItemsSource = texts;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var myValue = ((Button)sender).Tag;
foreach (var f in texts.ToList())
{
if (f.PKId.ToString() == myValue.ToString())
{
f._alignment = "Right";
MessageBox.Show(f._alignment);
}
}
}
private void Button_SourceUpdated(object sender, DataTransferEventArgs e)
{
var myValue = ((Button)sender).Tag;
foreach (var f in texts.ToList())
{
if (f.PKId.ToString() == myValue.ToString())
{
f._alignment = "Right";
MessageBox.Show(f._alignment);
}
}
}
}
public class ClassM : INotifyPropertyChanged
{
private string _id;
private int _pkid;
private string _text;
private double _fontSize = 10;
public bool _isChecked { get; set; }
public string _alignment="Left";
public int PKId
{
get { return _pkid; }
set
{
if (value != _pkid)
{
_pkid = value;
NotifyPropertyChanged();
}
}
}
public string Id
{
get { return _id; }
set
{
if (value != _id)
{
_id = value;
NotifyPropertyChanged();
}
}
}
public bool IsChecked
{
get { return _isChecked; }
set
{
if (value != _isChecked)
{
_isChecked = value;
NotifyPropertyChanged();
}
}
}
public string Text
{
get { return _text; }
set
{
if (value != _text)
{
_text = value;
NotifyPropertyChanged();
}
}
}
public double FontSize
{
get { return _fontSize; }
set
{
if (value != _fontSize)
{
_fontSize = value;
NotifyPropertyChanged();
}
}
}
public string Alignment
{
get { return _alignment; }
set
{
if (value != _alignment)
{
_alignment = value;
NotifyPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
The TextBox.TextAlignment property is of the enumeration type System.Windows.TextAlignment.
If you want to bind it without having to implement your own value converter then you want to populate the ComboBox with the actual enum values, not just a string with the same name like "Left" and "Right"...
Here's how you'd make a ComboBox represent TextAlignment:
<ComboBox>
<ComboBox.Items>
<TextAlignment>Left</TextAlignment>
<TextAlignment>Right</TextAlignment>
</ComboBox.Items>
</ComboBox>
Now you can bind the SelectedItem property of the ComboBox to the TextAlignment property of the TextBox.
Or in your case if you want to bind both to an underlying data context then you would need to change this:
private string _alignment = "Left";
To this:
private TextAlignment _alignment = TextAlignment.Left;
I'm really new to WPF so apologies in adavnced if this is an obvious question. I have a simple Checkbox in XAML as
<ListBox ScrollViewer.VerticalScrollBarVisibility="Auto"
ItemsSource="{Binding Selections}" >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid >
<CheckBox IsChecked="{Binding IsChecked}"
Content="{Binding Path=Item.SelectionName}" />
</Grid >
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Simplified code behind to allow bindings and INotifyPropertyChanged is:
public ObservableCollection<CheckedListItem<Selection>> Selections { get; set; }
public class Selection
{
public String SelectionName { get; set; }
}
Selections = new ObservableCollection<CheckedListItem<Selection>>();
Selections.Add(new CheckedListItem<Selection>(new Selection()
{ SelectionName = "SomeName" }, isChecked: true));
public class CheckedListItem<T> : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool isChecked;
private T item;
public CheckedListItem()
{ }
public CheckedListItem(T item, bool isChecked = false)
{
this.item = item;
this.isChecked = isChecked;
}
public T Item
{
get { return item; }
set
{
item = value;
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Item"));
}
}
public bool IsChecked
{
get { return isChecked; }
set
{
isChecked = value;
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("IsChecked"));
}
}
}
I now need to add an additional TextBox associated with each Checkbox, so in XAML I have
<ListBox ScrollViewer.VerticalScrollBarVisibility="Auto"
ItemsSource="{Binding Selections}" Margin="12,22,12,94">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid >
<CheckBox IsChecked="{Binding IsChecked}"
Content="{Binding Path=Item.SelectionName}" />
<<TextBox />
</Grid >
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I'm a bit stumped how to include this as part of the ObservableCollection and set it up the binding on both the CheckBox and associated TextBox? Both are being added together using Selections.Add(new CheckedListItem<Selection>(new Selection()
{ SelectionName = "SomeName" }, isChecked: true)); which is causing me some confusion.
EDIT: Added full code
public partial class SelectionSettingWindow : Window
{
public ObservableCollection<CheckedListItem<Selection>> Selections { get; set; }
public class Selection
{
public String SelectionName { get; set; }
public string SelectionTextField { get; set; }
}
public SelectionSettingWindow()
{
InitializeComponent();
Selections = new ObservableCollection<CheckedListItem<Selection>>();
string fg = #"Item1,true,TExtbox1text:Item2,true,TExtbox2text:Item3,false,TExtbox3text"; //Test String
string[] splitSelections = fg.Split(':');
foreach (string item in splitSelections)
{
string[] spSelectionSetting = item.Split(',');
bool bchecked = bool.Parse(spSelectionSetting[1].ToString());
string tbText = spSelectionSetting[2].ToString();
Selections.Add(new CheckedListItem<Selection>(new Selection()
{ SelectionName = spSelectionSetting[0].ToString(),
SelectionTextField = bText }, isChecked: bchecked));
}
DataContext = this;
}
public class CheckedListItem<T> : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool isChecked;
private T item;
private string textField;
public CheckedListItem()
{ }
public CheckedListItem(T item, bool isChecked = false)
{
this.item = item;
this.isChecked = isChecked;
}
public T Item
{
get { return item; }
set
{
item = value;
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Item"));
}
}
public bool IsChecked
{
get { return isChecked; }
set
{
isChecked = value;
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("IsChecked"));
}
}
public string TextField
{
get { return textField; }
set
{
textField = value;
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("TextField"));
}
}
}
}
<ListBox ScrollViewer.VerticalScrollBarVisibility="Auto"
ItemsSource="{Binding Selections}" Margin="12,22,12,94">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}"
Content="{Binding Path=Item.SelectionName}" />
<TextBox Text="{Binding Item.SelectionTextField, Mode=TwoWay}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
replace SelectionTextField above with whatever the field is that needs to be edited using the textbox on your Selection class.
Note that I changed the <Grid> to a <StackPanel> So they wouldn't appear on top of eachother and changed the bindings to TwoWay so the changes are reflected in the model.
Make sure your Selection class implements INotifyPropertyChanged (ObservableCollection updates the UI when things get added to/removed from the collection, it doesn't know anything about notifying when it's content's properties change so they need to do that on their own)
Implementing INotifyPropertyChanged on many classes can be cumbersome. I find implementing a base class useful for this. I've got this along with an extra reflection helper for raise property changed available here and a snippet I've made available. It's silverlight but it should work fine for WPF. Using the code I've provided via download you can simply type proprpc and hit tab and visual studio will stub in a property that notifies on change. Some explanation is in one of my old blog posts here and gives credit for where I based the code and snippet from.