Search code examples
wpfdatatemplate

How to update bindings inside DataTemplate?


Let's say I have the following ListView in my view

<ListView x:Name="ListView1" ItemsSource="{Binding SomeCollection}">
    <ListView.ContextMenu>
        <ContextMenu>
            <MenuItem Header="Do something" Command="{Binding SomeCommand, Mode=OneWay}" />
        </ContextMenu>
    </ListView.ContextMenu>
    <ListView.ItemTemplate>
        <DataTemplate DataType="model:Person">
            <StackLayout>
                <TextBlock Text="{Binding Name}">
                <Image Source="{Binding State, Converter={StaticResource StateToIconConverter}, Mode=OneWay}" />
            </StackLayout>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Now, this Person is a model and its properties do not have any way to inform the view of them being updated (according to MVVC). But, I need to update the view after SomeCommand gets executed, because items inside SomeCollection get edited.

I tried doing this

public void ExecuteSomeCommand() {
    // change the state of some person inside SomeCollection
    (ListView1.SelectedItems[0] as Person).State = "Some different state";

    // now inform the view of change, so it can reflect in the DataTemplate
    ListView1.GetBindingExpression(ListBox.ItemsSourceProperty).UpdateTarget();
}

And I thought this would propagate into the DataTemplate, but it doesn't. Is there any other way to do this? How should I change my approach?


Solution

  • When the model used in data binding implements the INotifyPropertyChanged Interface the UI is automatically updated when you modify a property of the model.

    public class Person : INotifyPropertyChanged
    {
        private Image _state;
        public Image State
        {
            get => _state;
            set {
                if (value != _state) {
                    _state = value;
                    OnPropertyChanged(nameof(State));
                }
            }
        }
    
        // ... other properties here ...
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        private void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }