在 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
我遇到一个问题,当基础数据 属性 发生变化时,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