在 LINQ 子句中更新 属性 会破坏 UI 的数据绑定

Updating a property inside a LINQ clause breaks databinding to UI

我遇到一个问题,当基础数据 属性 发生变化时,Silverlight UI 数据网格没有更新。如果我引入一个临时变量并更新一个块中的数据,我可以使它起作用,但不明白为什么原始代码不起作用。

这是网络 UI 部分的 xaml 代码:

<C1:C1DataGrid ItemsSource="{Binding DeliveryAccuracyTotals}" 
               HeadersVisibility="Column" 
               AutoGenerateColumns="False">
    <C1:C1DataGrid.Columns>
        <C1:DataGridDateTimeColumn Binding="{Binding PlannedAcceptanceDate}" 
                                   Header="{Binding Date, 
                                   Source={StaticResource res}}" 
                                   Format="dd.MM.yyyy" />
        <C1:DataGridNumericColumn Binding="{Binding OKcount}" 
                                  Header="{Binding OK, Source={StaticResource res}}" />
        <C1:DataGridNumericColumn Binding="{Binding NOKcount}" 
                                  Header="{Binding NOK, Source={StaticResource res}}" />
        <C1:DataGridNumericColumn Binding="{Binding OKpercentage}" 
                                  Header="%" Format="0.##"/>
    </C1:C1DataGrid.Columns>
</C1:C1DataGrid>

我有一个回调处理程序,用于在异步数据获取完成时处理数据:

private void handleDeliveryAccuracyReportDataCallBack(List<DeliveryAccuracyReportDataRow> data)
{
    DeliveryAccuracyTotals.Clear();
    if (data != null)
    {
        data.GroupBy(row => row.PlannedAcceptanceDate)
            .ToList()
            .ForEach(group => 
            DeliveryAccuracyTotals.Add(new DeliveryAccuracyTotalData(group.ToList())));
    }
}

这使用以下 属性 通知 UI 更改。

public List<DeliveryAccuracyTotalData> DeliveryAccuracyTotals
{
    get
    {
        if (_deliveryAccuracytotals == null)
        {
            _deliveryAccuracytotals = new List<DeliveryAccuracyTotalData>();
        }
        return _deliveryAccuracytotals;
    }
    private set
    {
        _deliveryAccuracytotals = value;
        NotifyPropertyChanged("DeliveryAccuracyTotals");
    }
}

如果我 运行 这样做,DeliveryAccuracyTotals 属性 会正确填充新数据,但 UI 不会显示新数据!

但是,当我将回调代码更改为此时,它起作用了:

private void handleDeliveryAccuracyReportDataCallBack(List<DeliveryAccuracyReportDataRow> data)
{
    var temp = new List<DeliveryAccuracyTotalData>();
    if (data != null)
    {
        data.GroupBy(row => row.PlannedAcceptanceDate)
        .ToList()
        .ForEach(group => 
        temp.Add(new DeliveryAccuracyTotalData(group.ToList())));
    }
    DeliveryAccuracyTotals = temp;
}

谁能解释一下这里发生了什么?我怀疑它与 ForEach() and/or 闭包有关。

只有当您为 DeliveryAccuracyTotals 字段设置新值时才会触发 NotifyPropertyChanged。您不会在列表发生变化时触发事件,只有在设置了全新列表时才触发。

如果 属性 是一个 ObservableCollection 那么 UI 将能够添加一个处理程序来获取集合本身的变异通知,而不仅仅是对保存列表的变量,但是如果您打算从头开始完全重新创建集合,而不是仅仅进行一些更改,那么为该 属性 分配一个新集合并不是真正的问题。

尽管 Servy 的分析是正确的,但我会说他的建议不是最好的。可观察的集合不会为你解决你的问题。每次重新绑定一个新集合也会重置树视图的状态(糟糕的用户体验)。

您应该查看各种 PropertyChanged 感知 Linq 查询实现。例如但不限于

  • 绑定 Linq
  • 连续 Linq
  • ReactiveUI 派生的可观察集合

我会推荐 RxUI