首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >INotifyPropertyChanged和INotifyCollectionChanged未被调用

INotifyPropertyChanged和INotifyCollectionChanged未被调用
EN

Stack Overflow用户
提问于 2020-12-17 14:47:22
回答 2查看 170关注 0票数 0

我已经为我的INotifyCollectionChanged中的各个项目实现了INotifyPropertyChanged (可能是不正确的)和INotifyPropertyChanged。一旦窗口为renderes(ContentRendered="Window_ContentRendered“,我将修改数据),以查看是否更新了DataGrid。我有两个问题。

  1. 当我调用“priceLadderData.data.Values.ChangePrice(1)”时,我可以看到OnPropertyChanged被击中了,但是没有任何变化是可见的。2.当我调用“priceLadderData.AddRow(新的PriceLadderRowData(99,99))”时,我得到以下错误:

异常:开发人员的信息(使用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:

代码语言:javascript
复制
<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:

代码语言:javascript
复制
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的时候接近了它几次,所以我真的很感激你的帮助。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-12-17 18:26:44

问题1.价格的更新。

当您更改价格时,在ChangePrice()函数中调用ChangePrice()。但是,在CallerMemberName中使用的“OnPropertyChanged”是将调用函数的名称作为属性名,在本例中是"ChangePrice“。但物业名称是“价格”。通常,在OnPropertyChanged属性的setter中调用:

代码语言:javascript
复制
   public float Price
    {
        get
        {
            return price;
        }
        private set
        {
            price = value;
            OnPropertyChanged();
        }
    }

问题2. SortedList.

我同意其他人的意见。使用ObservableCollection代替。有许多与XAML一起工作的功能。

但你想把它整理好。在这里,我已经更改了PriceLadderData类以处理这个问题:(纯粹主义者可能会说,您应该在XAML中这样做,并且您可以这样做,但是这里是代码中的。)

代码语言:javascript
复制
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:

代码语言:javascript
复制
    <DataGrid x:Name="dataGrid" ItemsSource="{Binding dataView}"

(删除ItemsSource构造函数中的MainWindow设置)

如果要添加数据或更改排序键,则必须刷新排序:

代码语言:javascript
复制
    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上的“私有”。

票数 3
EN

Stack Overflow用户

发布于 2020-12-17 16:51:16

您对NotifyCollectionChangedEventArgs()的使用是不正确的;您需要使用使用newItemsoldItems并填充它们的重载。

此外,您还通过公共data字段公开了您的(应该是)封装的集合。这将导致您走上一条糟糕的道路;它已经掩盖了您调用NotifyCollectionChangedEventArgs构造函数的方式的问题。如果代码中有类似于x.y.z.w()的调用,那么您就做错了什么。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65342924

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档