Tree View Hierarchical DataTemplate Binding - MVVM - c#

Here I'm trying to bind 'Solution' List to TreeView. Each 'Solution' has 'File' List and 'Solution Name'. I want to use Hierarchical DataTemplate to do this. In Debug mode I checked that 'Solution' List and 'File' list are successfully set. But in my view there is nothing shown.
In addition, in my view class when I try to set Data Type of the Hierarchical DataTemplate, it says "SolutionExplorerModel" does not exist int the namespace even though it does.
ViewModel
public class SolutionExplorerViewModel : INotifyPropertyChanged
{
private List<SolutionExplorerModel> _solutions = new List<SolutionExplorerModel>();
public List<SolutionExplorerModel> Solutions
{
get { return _solutions; }
set
{
_solutions = value;
RaisePropertyChanged("Solutions");
}
}
public SolutionExplorerViewModel()
{
Messenger.Default.Register<OpenFileDialog>(this, OnItemReceived);
}
private void OnItemReceived(OpenFileDialog openFile)
{
var solutionName = openFile.SafeFileName.Replace(".psim", "");
var files = new List<FileModel>();
var solutionPath = openFile.FileName.Replace(openFile.SafeFileName, "");
foreach(var file in Directory.EnumerateFiles(solutionPath, "*.xml"))
{
files.Add(new FileModel(file));
}
var newSolution = new SolutionExplorerModel
{
SolutionName = solutionName,
Files = files
};
_solutions.Add(newSolution);
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyThatChanged)
{
//checking if event is not null than raise event and pass
//in propperty name that has changed
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyThatChanged));
}
}
SolutionExplorerModel
public class SolutionExplorerModel : INotifyPropertyChanged
{
private string _solutionName;
public string SolutionName
{
get { return _solutionName; }
set
{
_solutionName = value;
RaisePropertyChanged("SolutionName");
}
}
private List<FileModel> _files;
public List<FileModel> Files
{
get { return _files; }
set
{
_files = value;
RaisePropertyChanged("Files");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyThatChanged)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyThatChanged));
}
}
FileModel
public class FileModel : INotifyPropertyChanged
{
private string _safeName;
public string SafeName
{
get { return _safeName; }
set
{
_safeName = value;
RaisePropertyChanged("SafeName");
}
}
private string _path;
public string Path
{
get { return _path; }
set
{
_path = value;
RaisePropertyChanged("Path");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyThatChanged)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyThatChanged));
}
public FileModel(string path)
{
this.Path = path;
this.SafeName = path.Split('\\').LastOrDefault();
}
}
View
<TreeView ItemsSource="{Binding Solutions}" DataContext="{Binding Source={StaticResource mainViewModelLocater}, Path=SolutionExplorerViewModel}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type model:SolutionExplorerModel}" ItemsSource="{Binding Files}">
<TextBlock Text="{Binding SolutionName}"></TextBlock>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>

This should work provided that the SolutionExplorerViewModel property of your mainViewModelLocater actually returns a populated SolutionExplorerViewModel:
<TreeView ItemsSource="{Binding Solutions}" DataContext="{Binding Source={StaticResource mainViewModelLocater}, Path=SolutionExplorerViewModel}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type model:SolutionExplorerModel}" ItemsSource="{Binding Files}">
<TextBlock Text="{Binding SolutionName}"></TextBlock>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type model:FileModel}">
<TextBlock Text="{Binding SafeName}" />
</DataTemplate>
</TreeView.Resources>
</TreeView>
Try to set the DataContext explicitly and make sure that you populate the Solutions collection:
treeView.DataContext = new SolutionExplorerViewModel();

Related

Databinding problem in Xamarin.Forms CollectionView

I'm having trouble finding a good way of changing a property of an object inside a list using a CollectionView in Xamarin.Forms.
Below is my code (only the relevant code for readability).
I have a list which I'm databinding to a CollectionView. Each entry in the collectionview contains a label with a number and two buttons to increase and decrease that number by 1.
Note that the code below is working fine. However, I'm not satisfied with the INotifyPropertyChanged implementation in my model, which should just be a simple DTO. I'd like to remove this interface from my model along with the OnPropertyChanged. When I do that, the label with the number doesn't change anymore when I click a button.
So I should make these changes in the ViewModel, but I haven't been able to figure out how. What would be an appropriate way of implementing this in the viewmodel so I can keep my model clean with only a simple property?
Note that the BaseViewModel already implements the INotifyPropertyChanged interface.
Xaml:
<CollectionView ItemsSource="{Binding MyList}" SelectionMode="Single">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Orientation="Horizontal">
<Button Text="-"
Command="{Binding Source={x:Reference MyPage}, Path=BindingContext.QuantityMinusCommand}"
CommandParameter="{Binding .}" />
<Label Text="{Binding Quantity, Mode=TwoWay}" />
<Button Text="+"
Command="{Binding Source={x:Reference MyPage}, Path=BindingContext.QuantityPlusCommand}"
CommandParameter="{Binding .}" />
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Viewmodel:
public class CollectionViewModel : BaseViewModel
{
private List<MyObject> _myList = new List<MyObject>();
public ICommand QuantityMinusCommand { get; }
public ICommand QuantityPlusCommand { get; }
public CollectionViewModel()
{
QuantityMinusCommand = new Command(OnQuantityMinusCommand);
QuantityPlusCommand = new Command(OnQuantityPlusCommand);
}
public List<MyObject> MyList
{
get => _myList;
set
{
_myList = value;
OnPropertyChanged("MyList");
}
}
private void OnQuantityMinusCommand(object o)
{
var myObject = (MyObject)o;
myObject.Quantity = --myObject.Quantity;
}
private void OnQuantityPlusCommand(object o)
{
var myObject = (MyObject)o;
myObject.Quantity = ++myObject.Quantity;
}
}
Model:
public class MyObject : System.ComponentModel.INotifyPropertyChanged
{
private int _quantity;
public int Quantity
{
get => _quantity;
set
{
_quantity = value;
OnPropertyChanged("Quantity");
}
}
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
{
var changed = PropertyChanged;
if (changed == null)
return;
changed.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
Your BaseViewModel can inherit INotifyPropertyChanged. And then your model can be a simple DTO.
public class BaseViewModel : ObservableObject
{
public BaseViewModel()
{
}
bool isBusy = false;
public bool IsBusy
{
get { return isBusy; }
set { SetProperty(ref isBusy, value); }
}
}
And the ObservableObject
/// <summary>
/// Observable object with INotifyPropertyChanged implemented
/// </summary>
public class ObservableObject : INotifyPropertyChanged
{
protected bool SetProperty<T>(ref T backingStore, T value,
[CallerMemberName]string propertyName = "",
Action onChanged = null)
{
if (EqualityComparer<T>.Default.Equals(backingStore, value))
return false;
backingStore = value;
onChanged?.Invoke();
OnPropertyChanged(propertyName);
return true;
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var changed = PropertyChanged;
if (changed == null)
return;
changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
And the model can be like this:
public class MyObject
{
public int Quantity { get; set; }
}
The viewmodel:
public class CollectionViewModel : BaseViewModel
{
// ...
}

TreeView WPF Binding

I'm using TreeView WPF.
I have the following class:
class MyFiles : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public string displayName;
public string fullPath;
public string DisplayName
{
get{return displayName;}
set{displayName = value; INofityPropertyChanged();}
}
public string FullName
{
get{return fullPath;}
set{fullPath = value; INofityPropertyChanged();}
}
private void INofityPropertyChanged(string propertyName="")
{
if(propertyName != null && PropertyChanged != null)
PropertyChanged (this, new PropertyChangedEventsArgs(propertyName);
}
}
I want to binding the class to TreeView.
What i'm tried:
<TreeView Name=treeViewFiles>
<TreeView.Resources>
<HierarcjocalDataTemplate DataType="x:Static local:MyFiles" ItemSource="{Binding MyFiles}">
<StackPanel Orientation="Horizontal">
<TextBlock Text={Binding DisplayName}>
<TextBlock Text={Binding FullName}>
</StackPanel>
</HierarcjocalDataTemplate>
<TreeView.Resources>
</TreeView>
.cs:
fileList = new ObservableCollection<MyFiles>();
fileList.Add(new MyFiles("Test","TestPath"));
treeViewFiles.ItemSource = fileList;
And i got something like a list instead tree :\
How can i fix my code to get a real tree with root etc?
Thanks!

Binding multi listbox itemsouce with 1 ObserverableCollection of usercontrol

I have two listbox define below:
<ListBox x:Name="RemoteListBox" HorizontalAlignment="Right" Margin="0,88.5,8,0"
Width="382.5"
HorizontalContentAlignment="Stretch"
ItemsSource ="{Binding RemoteItemsList}"
SelectedIndex="0">
</ListBox>
<ListBox x:Name="LibraryListBox"
Margin="4.5,88.5,437,0"
HorizontalContentAlignment="Stretch"
ItemsSource="{Binding LibraryItemsList}"
SelectedIndex="0">
</ListBox>
My viewmodel
private ObservableCollection<MotionTitleItem> _remoteItemsList;
public ObservableCollection<MotionTitleItem> RemoteItemsList
{
get { return _remoteItemsList; }
set
{
_remoteItemsList = value;
NotifyPropertyChanged("RemoteItemsList");
}
}
private ObservableCollection<MotionTitleItem> _libraryItemsList
public ObservableCollection<MotionTitleItem> LibraryItemsList
{
get { return _libraryItemsList; }
set
{
_libraryItemsList = value;
NotifyPropertyChanged("LibraryItemsList");
}
}
I bind two ListBox ItemSource with a ObserverableCollection define below:
var listMotion = new ObservableCollection<MotionTitleItem>();
foreach (MotionInfo info in listMotionInfo)
{
var motionTitleItem = new MotionTitleItem();
listMotion.Add(motionTitleItem);
}
viewModel.RemoteItemsList = listMotion;
viewModel.LibraryItemsList = listMotion;
MotionTitleItem is a custom user control.
My problem is only the first ListBox with ItemSource binding with RemoteListItem displays the Item in UI, the other doest not.
If I bind two ListBox ItemSource with 2 ObserverableCollection, the problem solved:
var listMotion = new ObservableCollection<MotionTitleItem>();
var listMotion2 = new ObservableCollection<MotionTitleItem>();
foreach (MotionInfo info in listMotionInfo)
{
var motionTitleItem = new MotionTitleItem();
listMotion.Add(motionTitleItem);
var motionTitleItem2 = new MotionTitleItem();
listMotion2.Add(motionTitleItem2);
}
viewModel.RemoteItemsList = listMotion;
viewModel.LibraryItemsList = listMotion2;
Could someone explain to me where is the point of the first scenario problem?
I don't know why you used two temporary list for this. You can directly add items to your Observable collection. Try this :
foreach (MotionInfo info in listMotionInfo)
{
viewModel.RemoteItemsList.Add(info);
viewModel.LibraryItemsList.Add(info);
}
Below, I tried to create the solution for you.
I assumed the model MotionTitleItem.
public class MotionTitleItem
{
string _name = string.Empty;
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged("Name");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
try
{
PropertyChangedEventHandler eventHandler = this.PropertyChanged;
if (null == eventHandler)
return;
else
{
var e = new PropertyChangedEventArgs(propertyName);
eventHandler(this, e);
}
}
catch (Exception)
{
throw;
}
}
}
My view model for this application is:
public class MotionTitleItemViewModel : INotifyPropertyChanged
{
ObservableCollection<MotionTitleItem> _remoteItemsList = new ObservableCollection<MotionTitleItem>();
public ObservableCollection<MotionTitleItem> RemoteItemsList
{
get { return _remoteItemsList; }
set { _remoteItemsList = value; }
}
ObservableCollection<MotionTitleItem> _libraryItemsList = new ObservableCollection<MotionTitleItem>();
public ObservableCollection<MotionTitleItem> LibraryItemsList
{
get { return _libraryItemsList; }
set { _libraryItemsList = value; }
}
public MotionTitleItemViewModel()
{
MotionTitleItem motion;
for (int i = 0; i < 10; i++)
{
motion = new MotionTitleItem();
motion.Name = "Name " + i.ToString();
this.LibraryItemsList.Add(motion);
this.RemoteItemsList.Add(motion);
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
try
{
PropertyChangedEventHandler eventHandler = this.PropertyChanged;
if (null == eventHandler)
return;
else
{
var e = new PropertyChangedEventArgs(propertyName);
eventHandler(this, e);
}
}
catch (Exception)
{
throw;
}
} }
My View is :
<Window x:Class="WPFExperiments.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListBox x:Name="RemoteListBox" HorizontalAlignment="Right" Margin="0,0.5,8,0"
Width="382.5"
HorizontalContentAlignment="Stretch"
ItemsSource ="{Binding RemoteItemsList}"
SelectedIndex="0">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ListBox x:Name="LibraryListBox"
Margin="4.5,0.5,437,0"
HorizontalContentAlignment="Stretch"
ItemsSource="{Binding LibraryItemsList}"
SelectedIndex="0">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
In code behind of this window i set DataContext to view model.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MotionTitleItemViewModel();
}}
This code is working for me.
Here is screenshot of the output.
Vote this answer if you find it useful.
Have fun!

Recursive databinding on treeview

I want to view a folder structure in a treeview using a databinding.
The folder class just has a property list of children and a property name.
If something changes it will fire the according event.
This is it:
public class Folder : INotifyPropertyChanged, INotifyCollectionChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public event NotifyCollectionChangedEventHandler CollectionChanged;
public Folder(string name)
{
this.Name = name;
this.ContentFolders = new List<Folder>();
}
public List<Folder> ContentFolders { get; set; }
public void AddFolder(Folder f)
{
this.ContentFolders.Add(f);
if (this.CollectionChanged != null)
{
this.NotifyCollectionChanged(
new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Add, f));
}
this.PropertyChanged(this, new PropertyChangedEventArgs("ContentFolders"));
}
private void NotifyCollectionChanged(NotifyCollectionChangedEventArgs e)
{
lock (CollectionChanged)
{
if (CollectionChanged != null)
{
Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => CollectionChanged(this, e)));
}
}
}
private string name;
public string Name
{
get
{
return this.name;
}
set
{
if (this.name != value)
{
this.name = value;
if (PropertyChanged != null)
{
PropertyChanged(
this, new PropertyChangedEventArgs("Name"));
}
}
}
}
}
This is my GUI, which shows the root folder in a treeview:
<Window x:Class="WpfApplication2.MyWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:WpfApplication2="clr-namespace:WpfApplication2"
Title="MyWindow" Height="300" Width="300" xmlns:u="clr-namespace:UpdateControls.XAML;assembly=UpdateControls.XAML">
<StackPanel>
<StackPanel.Resources>
<HierarchicalDataTemplate DataType="{x:Type WpfApplication2:Folder}"
ItemsSource="{Binding Path=ContentFolders}">
<TextBlock Text="{Binding Path=Name}" />
</HierarchicalDataTemplate>
</StackPanel.Resources>
<TreeView Name="TreeviewScenario">
<TreeViewItem Header="{Binding Path=RootFolder.Name}"
ItemsSource="{Binding Path=RootFolder.ContentFolders}" />
</TreeView>
<Button Content="Add Folder" Click="Button_Click" />
</StackPanel>
</Window>
The according MyWindow.xaml.cs class has a property Folder and adds some content. It has also a method for the button to add a new folder if it becomes clicked.
public partial class MyWindow : Window
{
public Folder RootFolder { get; set; }
public MyWindow()
{
this.RootFolder = new Folder("root");
this.RootFolder.ContentFolders.Add(new Folder("1"));
this.RootFolder.ContentFolders.Add(new Folder("12"));
this.RootFolder.ContentFolders.Add(new Folder("13"));
this.RootFolder.ContentFolders.Add(new Folder("14"));
this.RootFolder.ContentFolders.Add(new Folder("15"));
Folder aFolder = new Folder("aFolder");
aFolder.ContentFolders.Add(new Folder("2"));
aFolder.ContentFolders.Add(new Folder("21"));
aFolder.ContentFolders.Add(new Folder("22"));
aFolder.ContentFolders.Add(new Folder("23"));
aFolder.ContentFolders.Add(new Folder("24"));
this.RootFolder.ContentFolders.Add(aFolder);
this.DataContext = this;
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Folder c = new Folder("a new Folder");
this.RootFolder.AddFolder(c);
}
}
The Gui will be calles by a simple Main method with:
new MyWindow();
If I start, the treeview looks fine, it has all the items, which have been added in the MyWindow.xaml.cs.
But If I click the button, no new items will be shown. If I click the button before I expand the treeview, the new items will be there...
So the view seems not to be updated...
Can anybody see, what I have done wrong?
Change the ContentFolders in your Folder class to an ObservableCollection<> instead of a List<>
public ObservableCollection<Folder> ContentFolders { get; set; }

Add additional control to ObervableCollection

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.

Categories

Resources