我已经为我的INotifyCollectionChanged中的各个项目实现了INotifyPropertyChanged (可能是不正确的)和INotifyPropertyChanged。一旦窗口为renderes(ContentRendered="Window_ContentRendered“,我将修改数据),以查看是否更新了DataGrid。我有两个问题。
异常:开发人员的信息(使用Text读取此信息):引发此异常是因为控件“System.Windows.Controls.DataGrid Items.Count:5”的生成器“dataGrid”已接收到与项集合当前状态不一致的CollectionChanged事件序列。检测到以下差异:累计计数4与实际计数5不同。累计计数是(最后一次重置后的计数+ #Adds #删除)。在索引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, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e],[WPF_PriceLadder.PriceLadderRowData, WPF_Console2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]
最常见的原因是:(a)更改集合或其计数而不引发相应的事件;(b)引发具有不正确的索引或项参数的事件。
异常的堆栈跟踪描述了如何检测到不一致,而不是它们是如何发生的。要获得更及时的异常,请将生成器上附加的属性'PresentationTraceSources.TraceLevel‘设置为'High’并重新运行该场景。这样做的一种方法是运行一个类似于以下命令的命令:\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的时候接近了它几次,所以我真的很感激你的帮助。
发布于 2020-12-17 18:26:44
问题1.价格的更新。
当您更改价格时,在ChangePrice()函数中调用ChangePrice()。但是,在CallerMemberName中使用的“OnPropertyChanged”是将调用函数的名称作为属性名,在本例中是"ChangePrice“。但物业名称是“价格”。通常,在OnPropertyChanged属性的setter中调用:
public float Price
{
get
{
return price;
}
private set
{
price = value;
OnPropertyChanged();
}
}问题2. SortedList.
我同意其他人的意见。使用ObservableCollection代替。有许多与XAML一起工作的功能。
但你想把它整理好。在这里,我已经更改了PriceLadderData类以处理这个问题:(纯粹主义者可能会说,您应该在XAML中这样做,并且您可以这样做,但是这里是代码中的。)
public class PriceLadderData
{
public ObservableCollection<PriceLadderRowData> data { get; } = new ObservableCollection<PriceLadderRowData>();
public CollectionView dataView { get; private set; }
public PriceLadderData()
{
dataView = (CollectionView)CollectionViewSource.GetDefaultView(data);
dataView.SortDescriptions.Add(new SortDescription(nameof(PriceLadderRowData.Price), ListSortDirection.Ascending));
}
public void AddRow(PriceLadderRowData priceLadderRowData)
{
this.data.Add(priceLadderRowData);
}
public void Refresh()
{
//Refresh the sort order
dataView.Refresh();
}
}备注:添加了一个CollectionView (dataView),它将是将绑定到DataGrid的数据的排序视图。
在dataView的构造函数中设置PriceLadderData的排序指令。
将dataView绑定到XAML中的DataGrid:
<DataGrid x:Name="dataGrid" ItemsSource="{Binding dataView}"(删除ItemsSource构造函数中的MainWindow设置)
如果要添加数据或更改排序键,则必须刷新排序:
public void Window_ContentRendered(object sender, EventArgs e)
{
priceLadderData.data[0].ChangePrice(1);
priceLadderData.AddRow(new PriceLadderRowData(99, 99));
priceLadderData.Refresh();
}您还可以在数据上设置一个CollectionChanged事件,但这不会解决仅更改属性时的情况。
如果要更改DataGrid中的数据,则需要从DataGrid中移除"IsReadOnly=True“,并将其设置在各个列上。您还需要删除属性setter上的“私有”。
发布于 2020-12-17 16:51:16
您对NotifyCollectionChangedEventArgs()的使用是不正确的;您需要使用使用newItems和oldItems并填充它们的重载。
此外,您还通过公共data字段公开了您的(应该是)封装的集合。这将导致您走上一条糟糕的道路;它已经掩盖了您调用NotifyCollectionChangedEventArgs构造函数的方式的问题。如果代码中有类似于x.y.z.w()的调用,那么您就做错了什么。
https://stackoverflow.com/questions/65342924
复制相似问题