Search code examples
c#wpflistviewbindingfreezable

Automatic updte of ListView items


I am new to WPF Binding. Is there any way the listview automatically update when one of the item in ItemSource modifies its own dependecny property. I was trying it to do with FreezableCollection.

My code is given below and the aim is to update the listbox when the textbox is modified.

MainWindow.xaml

<Grid x:Name="mainDataGrid">
    <StackPanel Orientation="Horizontal">
        <ListView x:Name="membersListView" ItemsSource="{Binding}" MinWidth="100"/>
        <StackPanel>
            <TextBox x:Name="selectedItemTextBox" Text="{Binding ElementName=membersListView, Path=SelectedItem.Name, Mode=TwoWay}" MinWidth="200"/>
        </StackPanel>
    </StackPanel>
</Grid>

MainWindow.cs

public partial class MainWindow : Window
{
    ViewModel vm;
    public MainWindow()
    {
        InitializeComponent();
        vm = new ViewModel();
        vm.Add(new Model() { Name = "Name1" });
        vm.Add(new Model() { Name = "Name2" });
        this.DataContext = vm;
    }
}
public class Model : Freezable
    {
        public String Name
        {
            get { return (String)GetValue(NameProperty); }
            set { SetValue(NameProperty, value); }
        }
        public override string ToString()
        {
            return Name;
        }
        // Using a DependencyProperty as the backing store for Name.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty NameProperty =
            DependencyProperty.Register("Name", typeof(String), typeof(Model), new PropertyMetadata(""));

        protected override Freezable CreateInstanceCore()
        {
            return new Model();
        }
    }
    public class ViewModel : FreezableCollection<Model>
    {

    }

Solution

  • Ok, Right now your ListView is showing the String Representation of your models, That's why you had to override the "ToString()" method... because you couldn't get it to understand to show the Name property.

    Now what happens is that your TextBox changes the Name property well but your listbox doesn't know that "Name" property has changed... because it's looking at ToString()

    if you set the "DisplayMemberPath" of your ListView to "Name" , it will not look at ToString(), but rather "Name"... like this:

    <ListView x:Name="membersListView" ItemsSource="{Binding}" DisplayMemberPath="Name" MinWidth="100"/>
    

    Note that in this mode if you change the Name property using textbox, the textbox won't update the value of "Name" Property instantly until it loses focus, so to fix that change the binding of textbox text to this:

    <TextBox x:Name="selectedItemTextBox" Text="{Binding ElementName=membersListView, Path=SelectedItem.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" MinWidth="200"/>
    

    I've added "UpdateSourceTrigger=PropertyChanged" to ensure that as you start changing the text of TextBox, the Name property is updated instantly.

    :) hope it helps.