ListView在ObservableCollection项属性更改时未更新ItemSource

4
请查看以下示例代码:
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)
        {

        }
    }
}

如果我在ObservableCollection中添加或删除任何项目,它会正确更新View中的ListView,但问题是如果我修改ObservableCollection项属性,则ListView不会更新。
例如: 点击上面指定的按钮后,它 a. 添加一个新项目(在ListView中成功反映) b. 修改第一个项目的FirstName(未在ListView中反映)
我应该怎么做才能使修改反映在View中。
如果有人能指出我做错了什么,我将非常感激。

2
这是简化的代码版本还是你在 OnPropertyChanged 方法中真的没有触发 INPC.PropertyChanged 事件?你获取到了处理程序,但你没有触发事件:handler(this, new PropertyChangedEventArgs(name)); - dkozl
2个回答

5
ObservableCollection事件在更改项目时不触发,只有在添加、删除或移动项目时才会触发。您必须在项类中实现INotifyPropertyChanged接口,并在集合中注册每个项的事件。
请参见此处 如果您对集合进行了大量更改,则可以触发NotifyCollectionChangedAction.Reset事件将它们全部重置。
请参见此处

我已阅读了那个链接并实施了类似的方法,但没有成功,然后再次检查。在调试时发现它没有进入EntityViewModelPropertyChanged()方法。我应该发布这段代码吗? - Parshuram
请确保对于每个项目都调用了 item.PropertyChanged += EntityViewModelPropertyChanged;。您可以发布您的代码。 - Eric Bole-Feysot
发布了代码。对于ObservableCollection中的每个fullname项,item.PropertyChanged += EntityViewModelPropertyChanged都会被调用。但是在进行更改时,控件不会转到EntityViewModelPropertyChanged。 - Parshuram
1
这是你真正的代码吗?你看到了dkozl的评论吗? - Eric Bole-Feysot
这很尴尬。事件未被触发。非常抱歉浪费了您的时间。也非常感谢@dkozl。 - Parshuram
你还需要指定绑定模式为单向: Text="{x:Bind Title, Mode=OneWay}" - Slion

0

我在WinUI中使用ListViewObservableCollection时也遇到了同样的问题。

你需要明白的是,ObservableCollection只负责通知集合变化。项目级别的更改通过INotifyPropertyChanged处理。但是,为了应用这些更改,您需要确保绑定模式至少是单向的,如果需要,则为双向的。

您的XAML应该如下所示: Text="{x:Bind Title, Mode=OneWay}"

不要尝试那里提出的建议,那是错误的: ObservableCollection not noticing when Item in it changes (even with INotifyPropertyChanged)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接