WPF MVVM可观察集合不更新GUI

5
我正在设计一个MVVM WPF应用程序,有一个名为SelectedCustomer的属性,类型为Customer的ViewModel。此对象具有一个名为SummaryDetails的属性,类型为ObservableCollection,它逐行呈现为ListView。
为此,我在ViewModel上创建了一个名为CustomerSummaryDetails的单独属性,其中仅包含一个get,它返回上述客户中包含的集合。
在XAML中,我将ItemsSource绑定到CustomerSummaryDetails属性。
这样做是因为我不想绑定到SelectedCustomer.SummaryDetails,因为那样不够干净。
SelectedCustomer属性有一个get和一个set方法,set方法调用OTHER属性的OnPropertyChanged,即CustomerSummaryDetails,让XAML知道底层集合已更改并进行更新。
问题是,当我更新集合中的项时,尽管所有正确的事件都被调用,但它没有反映在GUI上。我已经跟踪了SelectedCustomer的set方法,并遵循了OnPropertyChanged(“CustomerSummaryDetails”)调用,它按预期进入了CustomerSummaryDetails属性的“get”方法。此时,我已深入了解了返回的集合的值,并且列表内的值已更新,但是在GUI上没有反映,所以我感到困惑,因为GUI似乎正在调用get方法来更新它OnPropertyChanged()调用,但它在视觉上没有反映出来。
更新-包括代码
抱歉没有包括代码,我认为仅描述会更容易,但以下是主要的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代码:
    <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>

最后,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;
}

尽管您说的是“客户”类型,但“客户”的数据类型是什么?它是一个强类型类对象,还是一个数据表的数据行等? - DRapp
你的CustomerSummaryDetails属性的签名是什么?我建议发布一些源代码而不是描述,这可能更容易。 :-) - AlSki
你的绑定模式设置为什么? - Bob.
你是否尝试在XAML中将Binding Mode设置为TwoWay? - BryanJ
1个回答

23

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

更改未在UI中反映出来,因为当您使用NotifyPropertyChange()来通知整个集合时,而不是单个项目的单个属性时,WPF检测到实际上与以前相同的实例(指向相同集合的同一对象引用),因此似乎没有任何更改。


作为补充说明,你为什么要对集合使用 foreach 并在第一项上中断?将其替换为 FirstOrDefault() 或其他类似方法并删除 foreach。 - Federico Berasategui
请问,如果我有一个简单的集合(没有可观察对象),我该如何更新或重新绑定数据?哪种方法最好?谢谢。 - Serhii Kyslyi
@СергійКислий 这是一个独立的问题,最好发布一个新问题。 - Federico Berasategui
问题 - 如果我们手动提高整个集合的属性更改,我们是否仍然需要对单个属性进行更改? - aggietech
1
如果集合保持不变,那么是的。这正是答案所说的。 - Federico Berasategui

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