WPF MVVM 可观察集合不更新 GUI

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13144320/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 06:00:14  来源:igfitidea点击:

WPF MVVM observable collection not updating GUI

c#wpfmvvmobservablecollection

提问by NZJames

Im designing an MVVM WPF app, and have a ViewModel which has a property called SelectedCustomer, of type Customer. This object has a property called SummaryDetails of type ObservableCollection which renders into a ListView, line by line.

我正在设计一个 MVVM WPF 应用程序,并有一个 ViewModel,它有一个名为 SelectedCustomer 的属性,类型为 Customer。该对象有一个名为 SummaryDetails 的属性,其类型为 ObservableCollection,它逐行呈现到 ListView 中。

To do this, I have created a separate property on the ViewModel called CustomerSummaryDetails which contains simply a get, that returns the collection contained within the customer I mentioned above.

为此,我在 ViewModel 上创建了一个名为 CustomerSummaryDetails 的单独属性,它只包含一个 get,它返回我上面提到的客户中包含的集合。

In the XAML I have bound the ItemsSource to the CustomerSummaryDetails Property.

在 XAML 中,我已将 ItemsSource 绑定到 CustomerSummaryDetails 属性。

This was so I didnt have to bind to SelectedCustomer.SummaryDetails which isn't as clean.

这样我就不必绑定到不太干净的 SelectedCustomer.SummaryDetails。

The SelectedCustomer property has a get and a set method, and the set calls OnPropertyChanged for the OTHER property, CustomerSummaryDetails, letting the XAML know that the underlying collection has changed and to update.

SelectedCustomer 属性有一个 get 和一个 set 方法,并且该 set 为 OTHER 属性 CustomerSummaryDetails 调用 OnPropertyChanged,让 XAML 知道基础集合已更改并进行更新。

The problem is though that when I update an item within the collection, it is not reflecting on the GUI, despite all the right events being called. I have stepped in and the set method of the SelectedCustomer is being called, and I then follow the OnPropertyChanged("CustomerSummaryDetails") call which goes into the "get" method of the CustomerSummaryDetails property as expected. I have delved into the value of the returned collection at this point, and the value within the list is the updated value, however nothing is getting reflected on the GUI, so I am puzzled as it seems the GUI is calling the get method to update it on the OnPropertyChanged() call, but it is not reflecting visually.

问题是,当我更新集合中的项目时,尽管调用了所有正确的事件,但它并没有反映在 GUI 上。我已经介入并调用 SelectedCustomer 的 set 方法,然后我按照预期进入 CustomerSummaryDetails 属性的“get”方法的 OnPropertyChanged("CustomerSummaryDetails") 调用。此时我已经深入研究了返回集合的值,列表中的值是更新后的值,但是 GUI 上没有任何反映,所以我很困惑,因为 GUI 似乎正在调用 get 方法来更新它在 OnPropertyChanged() 调用中,但它没有在视觉上反映。

UPDATE - CODE INCLUDED

更新 - 包含代码

Sorry for not including code, I thought it would be easier to just describe but here are the main ViewModel properties

抱歉没有包含代码,我认为只描述会更容易,但这里是主要的 ViewModel 属性

public CustomerSummaryViewModel SelectedCustomer
{
    get { return _selectedCustomer; }
    set
    {
        _selectedCustomer = value;
        OnPropertyChanged("CustomerSummaryDetails");
    }
}

public ObservableCollection<RbcUICustomerSummary> CustomerSummaryDetails
{
    get { return _selectedCustomer.SummaryDetails; }
}

public ItemSummaryViewModel SelectedItem
{
    get { return _selectedItem; }
    set
    {
        _selectedItem = value;
        OnPropertyChanged("SelectedItem");
    }
}

XAML below

下面的 XAML

    <ListView x:Name="lvCustomerSummary" Margin="10,10,10,10" Background="#F4F8FB" ItemsSource="{Binding CustomerSummaryDetails}" MouseDoubleClick="lvCustomerSummary_MouseDoubleClick" ItemContainerStyle="{StaticResource myHeaderStyleColor}" VirtualizingStackPanel.IsVirtualizing="False" VirtualizingStackPanel.VirtualizationMode="Recycling">
            <ListView.View>
            <GridView ColumnHeaderContainerStyle="{StaticResource myHeaderStyle}">
                    <GridView.Columns>
                    <GridViewColumn Header=""  >
                        <GridViewColumn.CellTemplate>
                            <DataTemplate >
                                <Grid>
                                    <Image Source="{z:ImageStaticResource {Binding IconSelect}}" Width="20" Height="20" />
                                </Grid>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                    <GridViewColumn Width="200" Header="SubCustType" DisplayMemberBinding="{Binding SubCustType}" >
                    </GridViewColumn>
                    <GridViewColumn Width="200" Header="SubCustValue"  DisplayMemberBinding="{Binding SubCustValue}">
                    </GridViewColumn>
                    <GridViewColumn Header=""  >
                        <GridViewColumn.CellTemplate>
                            <DataTemplate >
                                <Grid>
                                    <Image Source="{z:ImageStaticResource {Binding IconFlag}}" Width="20" Height="20" />
                                </Grid>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                </GridView.Columns>
            </GridView>
        </ListView.View>
    </ListView>

And finally the Updater method which does the actual update

最后是进行实际更新的 Updater 方法

private void DisplayCustomerComment(string commentEnt)
{            
    if (_queueViewModel.SelectedCustomer == null) return;
        var selCust = _queueViewModel.SelectedCustomer;

    foreach (var t in selCust.SummaryDetails
        .Where(t => t.SubCustType == AppString.CustomerSummary.Comment))
    {
        t.SubCustValue = commentEnt;
        break;
    }

    _queueViewModel.SelectedCustomer = selCust;
}

回答by Federico Berasategui

You're not modifying the ObservableCollection itself (such as adding/removing items) but the items INSIDE that collection. The ObservableCollection is responsible for notifying its own changes, not changes pertaining to its items. You Should NotifyPropertyChange("SubCustValue") in the setter of your SubCustValue.

您不是在修改 ObservableCollection 本身(例如添加/删除项目),而是修改该集合内的项目。ObservableCollection 负责通知自己的更改,而不是与其项目相关的更改。您应该在您的 SubCustValue 的 setter 中 NotifyPropertyChange("SubCustValue")。

The change is not being reflected in the UI because when you NotifyPropertyChange() the entire collection, instead of the indiviual property of the individual item, WPF detects it is actually the same instance (the same object reference to the same collection) as before, so nothing seems to have changed.

更改未反映在 UI 中,因为当您 NotifyPropertyChange() 整个集合时,WPF 检测到它实际上是与以前相同的实例(对相同集合的相同对象引用),而不是单个项目的单个属性,所以似乎什么都没有改变。