4

Consider the following Sample Code :

View.xml

<Grid>
    <ListView Name="NameList" HorizontalAlignment="Left" Height="142" Margin="55,45,0,0" VerticalAlignment="Top" Width="389">
        <ListView.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="Auto"/>
                    </Grid.ColumnDefinitions>
                    <Label Content="{Binding FirstName}"/>
                    <Label Content="{Binding LastName}" Grid.Column="1"/>
                </Grid>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
    <Button Content="Button" HorizontalAlignment="Left" Margin="120,256,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>

</Grid>

View.xml.cs

public partial class MainWindow : Window
{
    ViewModel vm;
    public MainWindow()
    {
        InitializeComponent();
        vm = new ViewModel();
        this.DataContext = vm;
        NameList.ItemsSource = vm.fn;
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        vm.fn.Add(new fullname("P", "Q"));
        vm.fn[0].FirstName = "NewName";
    }

}

ViewModel.cs

class ViewModel : INotifyPropertyChanged
{

    public ViewModel()
    {
        fn = new ObservableCollection<fullname>();
        fn.CollectionChanged += ContentCollectionChanged;
        fn.Add(new fullname("A", "B"));
        fn.Add(new fullname("C", "D"));
    }

    public void ContentCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == NotifyCollectionChangedAction.Remove)
        {
            foreach (fullname item in e.OldItems)
            {
                //Removed items
                item.PropertyChanged -= EntityViewModelPropertyChanged;
            }
        }
        else if (e.Action == NotifyCollectionChangedAction.Add)
        {
            foreach (fullname item in e.NewItems)
            {
                //Added items
                item.PropertyChanged += EntityViewModelPropertyChanged;
            }
        }
    }

    public void EntityViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        //This will get called when the property of an object inside the collection changes
    }

    public ObservableCollection<fullname> _fn;
    public ObservableCollection<fullname> fn
    {
        get { return _fn; }
        set { _fn = value; OnPropertyChanged("fn"); }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {

        }
    }
}

Model.cs

class fullname : INotifyPropertyChanged
{
    public fullname(string f, string l)
    {
        FirstName = f;
        LastName = l;
    }

    public string _FirstName;
    public string FirstName
    {
        get { return _FirstName; }
        set { _FirstName = value; OnPropertyChanged("FirstName"); }
    }


    public string _LastName;
    public string LastName
    {
        get { return _LastName; }
        set { _LastName = value; OnPropertyChanged("LastName"); }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {

        }
    }
}

If I add or remove any items in the ObservableCollection it updates the ListView in the View correctly but the problem is that if i modify the ObservableCollection item property the ListView is not updated.

for ex: On click of above specified button it
a. Adds a new item (Successfully reflected in the ListView)
b. Modify FirstName of first item (Not reflected in the ListView)

What should i do so as to make the modifications reflect in View.

I would be very thankful if anyone could point out what i am doing wrong.

Parshuram
  • 67
  • 1
  • 8
  • 2
    Is it simplified code version or you really don't raise `INPC.PropertyChanged` event in `OnPropertyChanged` method? You get handler but you don't raise the event: `handler(this, new PropertyChangedEventArgs(name));` – dkozl Jan 27 '15 at 12:08

2 Answers2

5

ObservableCollection event are not fired when an item is changed, only when it is added, removed or moved. You must implement INotifyPropertyChanged interface in item class, and register each item event in collection.

See here

If you make heavy changes in the collection, you can raise a

NotifyCollectionChangedAction.Reset

event to reset them all

See here

Community
  • 1
  • 1
Eric Bole-Feysot
  • 13,949
  • 7
  • 47
  • 53
  • I had read that link and had implemented likewise but no success and again rechecked. On debugging found it does not enter the EntityViewModelPropertyChanged(). Should i post the code? – Parshuram Jan 27 '15 at 12:22
  • Be sure the item.PropertyChanged += EntityViewModelPropertyChanged; is called for each item. You can post your code. – Eric Bole-Feysot Jan 27 '15 at 12:33
  • Posted the code. item.PropertyChanged += EntityViewModelPropertyChanged is called for each fullname item in the ObservableCollection. But on making changes the control does not go to EntityViewModelPropertyChanged. – Parshuram Jan 27 '15 at 13:30
  • 1
    Is it your real code ? did you see the dkozl comment ? – Eric Bole-Feysot Jan 27 '15 at 13:32
  • This is embarrassing. Did not raise event. Really sorry for wasting your time. Many Thanks also to @dkozl – Parshuram Jan 27 '15 at 13:35
  • You also need to specify the binding mode to be one way: `Text="{x:Bind Title, Mode=OneWay}"`. – Slion Feb 05 '22 at 16:29
0

I was also struggling with the same issue on WinUI with ListView and ObservableCollection.

What you need to understand is that ObservableCollection is only responsible to notify collection changes. Item level change are handle through INotifyPropertyChanged. However for those to be applied you need to make sure your binding mode is at least one way, two way if you need to.

Your XAML should look like that: Text="{x:Bind Title, Mode=OneWay}

Do not attempt what's proposed there, it's just wrong: ObservableCollection not noticing when Item in it changes (even with INotifyPropertyChanged)

Slion
  • 2,558
  • 2
  • 23
  • 27