【发布时间】:2020-12-18 02:26:44
【问题描述】:
我已经为我的 DataGrid 中的各个项目实现了 INotifyCollectionChanged(可能不正确)和 INotifyPropertyChanged。 一旦 Window 被渲染(ContentRendered="Window_ContentRendered" ),我会修改数据以查看 DataGrid 是否得到更新。 我有 2 个问题。
- 当我调用“priceLadderData.data.Values[0].ChangePrice(1);”时我可以看到 OnPropertyChanged 被击中,但没有可见的变化。 2.当我调用“priceLadderData.AddRow(new PriceLadderRowData(99, 99));”时我收到以下错误:
例外:开发人员信息(使用文本可视化工具阅读 this): 抛出这个异常是因为生成器用于控制 'System.Windows.Controls.DataGrid Items.Count:5' 名称为 'dataGrid' 已收到不同意的 CollectionChanged 事件序列 与 Items 集合的当前状态。以下 检测到差异:累计计数 4 与 实际计数 5. [累计计数为 (Count at last Reset + #Adds - #Removes since last Reset)。] 在索引 0:生成器的项目 '[364525, WPF_PriceLadder.PriceLadderRowData]' 与实际项目不同 '[99,WPF_PriceLadder.PriceLadderRowData]'。在索引 1:发电机的 项目“[364550,WPF_PriceLadder.PriceLadderRowData]”不同于 实际项目“[364525,WPF_PriceLadder.PriceLadderRowData]”。在索引 2:生成器的项目 '[364575, WPF_PriceLadder.PriceLadderRowData]' 是 与实际项目不同'[364550, WPF_PriceLadder.PriceLadderRowData]'。 (……还有 1 个实例……)
以下一个或多个来源可能引发了错误事件: System.Windows.Controls.ItemContainerGenerator System.Windows.Controls.ItemCollection MS.Internal.Data.EnumerableCollectionView * System.Collections.Generic.SortedList`2[[System.Single, System.Private.CoreLib,版本=5.0.0.0,文化=中性, PublicKeyToken=7cec85d7bea7798e],[WPF_PriceLadder.PriceLadderRowData, WPF_Console2,版本=1.0.0.0,文化=中性,PublicKeyToken=null]] (加星标的来源被认为更有可能是导致 问题。)
最常见的原因是 (a) 更改集合或其计数 不引发相应的事件,并且 (b) 引发事件 不正确的索引或项目参数。
异常的堆栈跟踪描述了不一致是如何产生的 检测到,而不是它们是如何发生的。要获得更及时的异常,请设置 附加属性“PresentationTraceSources.TraceLevel” 生成器将值设置为“高”并重新运行场景。一种方法来做到这一点 是运行类似于以下的命令:\n
System.Diagnostics.PresentationTraceSources.SetTraceLevel(myItemsControl.ItemContainerGenerator, System.Diagnostics.PresentationTraceLevel.High) 从即时 窗户。这会导致检测逻辑在每个 CollectionChanged 事件,因此它会降低应用程序的速度。
MainWindow.xaml:
<Window x:Class="WPF_PriceLadder.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPF_PriceLadder"
mc:Ignorable="d"
ContentRendered="Window_ContentRendered"
Title="MainWindow" Height="450" Width="400">
<Grid>
<DataGrid x:Name="dataGrid"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"
IsManipulationEnabled="False"
IsReadOnly="True"
AllowDrop="False"
CanUserAddRows="False"
CanUserDeleteRows="False"
EnableColumnVirtualization="True"
CanUserReorderColumns="False"
CanUserSortColumns="False"
CanUserResizeRows="False"
SelectionMode="Single"
FontWeight="Normal"
AutoGenerateColumns="False"
SelectionUnit="Cell"
>
<DataGrid.Columns>
<DataGridTextColumn Header="Price" Binding="{Binding Value.Price, UpdateSourceTrigger=PropertyChanged,NotifyOnSourceUpdated=True}">
</DataGridTextColumn>
<DataGridTextColumn Header="Volume" Binding="{Binding Value.Volume,UpdateSourceTrigger=PropertyChanged}">
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
MainWindow.xaml.cs:
using System;
using System.Collections.Generic;
using System.Windows;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Collections.Specialized;
namespace WPF_PriceLadder
{
public partial class MainWindow : Window
{
public PriceLadderData priceLadderData;
public MainWindow()
{
priceLadderData = new PriceLadderData();
FillUpWithDummyRows(priceLadderData);
this.DataContext = priceLadderData;
InitializeComponent();
dataGrid.ItemsSource = priceLadderData.data;
}
public void FillUpWithDummyRows(PriceLadderData priceLadderData)
{
priceLadderData.AddRow(new PriceLadderRowData(364600, 37));
priceLadderData.AddRow(new PriceLadderRowData(364575, 18));
priceLadderData.AddRow(new PriceLadderRowData(364550, 30));
priceLadderData.AddRow(new PriceLadderRowData(364525, 20));
}
public void Window_ContentRendered(object sender, EventArgs e)
{
priceLadderData.data.Values[0].ChangePrice(1);
priceLadderData.AddRow(new PriceLadderRowData(99, 99));
}
}
public class PriceLadderRowData : IComparable, INotifyPropertyChanged
{
private float price;
private int volume = 0;
public event PropertyChangedEventHandler PropertyChanged;
public float Price
{
get
{
return price;
}
private set
{
price = value;
}
}
public int Volume
{
get
{
return volume;
}
private set
{
volume = value;
}
}
public PriceLadderRowData(float price, int volume)
{
this.Price = price;
this.Volume = volume;
}
public int CompareTo(object obj)
{
return Price.CompareTo(obj);
}
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
public void ChangePrice(float price)
{
this.Price = price;
OnPropertyChanged();
}
}
public class PriceLadderData : INotifyCollectionChanged
{
public event NotifyCollectionChangedEventHandler CollectionChanged;
public SortedList<float, PriceLadderRowData> data = new SortedList<float, PriceLadderRowData>();
public PriceLadderData()
{
}
protected void OnCollectionChanged([CallerMemberName] string name = null)
{
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add));
}
public void AddRow(PriceLadderRowData priceLadderRowData)
{
this.data.Add(priceLadderRowData.Price, priceLadderRowData);
OnCollectionChanged();
}
}
}
这里有什么问题吗?还没有键盘坏过,但我在学习 WPF 和 XAML 时几次接近它,所以我真的很感谢你的帮助。
【问题讨论】:
-
为什么你发明了自己的东西而不是仅仅使用 observablecollection?我建议您在学习时首先使用开箱即用的东西。我还建议您使用 mainwindowviewmodel 作为主窗口的 datacontect 并绑定 itemssource 而不是设置它。此外,删除 UpdateSourceTrigger=PropertyChanged,用户无法输入任何内容,因此毫无意义。