【问题标题】:ItemPropertyChanged not working on observableCollection.Why?ItemPropertyChanged 在 observableCollection 上不起作用。为什么?
【发布时间】:2010-10-03 10:19:29
【问题描述】:

我已经到处寻找解决方案,但我似乎没有深入了解它。 像网上的许多帖子一样,我似乎没有让我的 itemPropertyChanged 工作。 编辑集合中的项目时它不会触发。为什么。

有点长,但这是我整理的一个例子。

我有一个包含 OrderViewModel 集合的 customerViewModel 在数据网格中编辑订单时,该事件不会触发。

我已经实现了以下内容,但只有在加载时编辑时才被触发。 好像不是同一个集合的东西……

INotifyPropertyChanged inpc = OrderViewModels;
inpc.PropertyChanged += OnItemPropertyChanged; 

有什么建议吗?快把我逼疯了

型号

public class Order
{
    public int Id { get; set; }
    public string Description { get; set; }
    public int CustomerId{ get; set; }
}

public class Customer
{
    public Customer()
    {
        Orders=new ObservableCollection<Order>();
    }

    public int Id { get; set; }
    public string Name { get; set; }
    public string Surname{ get; set;}
    public ObservableCollection<Order> Orders{ get; set;}

}

视图模型

public class CustomerViewModel : ViewModelBase
{
    private Customer _customerModel;

    public CustomerViewModel(Customer customerModel)
    {
        _customerModel = customerModel;
        _orderViewModels = new ObservableCollection<OrderViewModel>();
        OrderViewModels.CollectionChanged += OnOrdersCollectionChanged;
        INotifyPropertyChanged inpc = OrderViewModels;
        inpc.PropertyChanged += OnItemPropertyChanged; 

    }

    private void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        //not firing!!!!!!!!!!!!!!!!!!!!!!!!!
    }

    void OnOrdersCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        switch (e.Action)
        {
            case NotifyCollectionChangedAction.Add:
                _customerModel.Orders.Insert(e.NewStartingIndex, ((OrderViewModel)e.NewItems[0]).OrderModel);
                break;
            case NotifyCollectionChangedAction.Remove:
                _customerModel.Orders.RemoveAt(e.OldStartingIndex);
                break;
            case NotifyCollectionChangedAction.Replace:
                _customerModel.Orders[e.OldStartingIndex] = ((OrderViewModel)e.NewItems[0]).OrderModel;
                break;
            case NotifyCollectionChangedAction.Move:
                _customerModel.Orders.Move(e.OldStartingIndex, e.NewStartingIndex);
                break;

            default:
                throw new ArgumentOutOfRangeException();
        }
    }

    public int Id
    {
        get { return _customerModel.Id; }
        set
        {
            _customerModel.Id = value;
            OnPropertyChanged("Id");
        }
    }

    public string Name
    {
        get { return _customerModel.Name; }
        set
        {
            _customerModel.Name = value;
            OnPropertyChanged("Name");
        }
    }

    public string Surname
    {
        get { return _customerModel.Surname; }
        set
        {
            _customerModel.Surname = value;
            OnPropertyChanged("Surname");
        }
    }
    public Customer CustomerModel
    {
        get { return _customerModel; }
        set
        {
            _customerModel = value;
            OnPropertyChanged("");
        }
    }

    private ObservableCollection<OrderViewModel> _orderViewModels;

    public ObservableCollection<OrderViewModel> OrderViewModels
    {
        get { return _orderViewModels; }
        set
        {
            _orderViewModels = value;
            OnPropertyChanged("OrderViewModels");
        }
    }
}

public class OrderViewModel:ViewModelBase
{
    private Order _orderModel;

    public OrderViewModel(Order orderModel)
    {
        _orderModel = orderModel;
    }

    public int Id
    {
        get { return _orderModel.Id; }
        set
        {
            _orderModel.Id = value;
            OnPropertyChanged("Id");
        }
    }
    public int CustomerId
    {
        get { return _orderModel.CustomerId; }
        set
        {
            _orderModel.CustomerId = value;
            OnPropertyChanged("CustomerId");
        }
    }
    public string Description 
    {
        get { return _orderModel.Description; }
        set
        {
            _orderModel.Description = value;
            OnPropertyChanged("Description");
        }
    }

    public Order OrderModel
    {
        get { return _orderModel; }
        set
        {
            _orderModel = value;
            OnPropertyChanged("");
        }
    }
}

存储库

public class OrderRepository
{
    public static ObservableCollection<Order> GetOrders(int customerId)
    {
        return new ObservableCollection<Order>
               {
                   new Order {Id = 1, CustomerId=1, Description = "MotherBoard"},
                   new Order {Id = 2, CustomerId=1,Description = "Video Card"},
                   new Order {Id = 3, CustomerId=1,Description = "TV"},
                   new Order {Id = 4, CustomerId=1, Description = "Video Recorder"},
                   new Order {Id = 5, CustomerId=1,Description = "Speakers"},
                   new Order {Id = 6, CustomerId=1,Description = "Computer"}
               };
    }
}

查看

public partial class OrdersView
{
    public OrdersView()
    {
        InitializeComponent();

        if (!DesignerProperties.GetIsInDesignMode(this))
        {
            var customerVm =
                new CustomerViewModel(new Customer
                                          {
                                              Id = 1,
                                              Name = "Jo",
                                              Surname = "Bloggs"
                                          });

            var orders = OrderRepository.GetOrders(1);
            foreach (var orderModel in orders)
            {
                customerVm.OrderViewModels.Add(new OrderViewModel(orderModel));
            }
            DataContext = customerVm;
        }
    }
}

Xaml

<Grid>
    <DataGrid AutoGenerateColumns="False" AlternationCount="2" ItemsSource="{Binding Path=OrderViewModels}">
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding Id}" Header="Id"/>
            <DataGridTextColumn Binding="{Binding CustomerId}" Header="Customer Id"/>
            <DataGridTextColumn Header="Description" Binding="{Binding Description,UpdateSourceTrigger=PropertyChanged}"/>
        </DataGrid.Columns>
    </DataGrid>
</Grid>

【问题讨论】:

标签: c# wpf


【解决方案1】:
    INotifyPropertyChanged inpc = OrderViewModels;
    inpc.PropertyChanged += OnItemPropertyChanged; 

ObservableCollection&lt;T&gt; 中的任何属性发生更改时,该代码会通知您,ObservableCollection&lt;T&gt; 中的项目属性发生更改时不会通知您。例如,当您添加或删除 OrderViewModel 时应调用您的处理程序,因为 Count 属性将在 ObservableCollection&lt;OrderViewModel&gt; 上发生变化。

没有任何东西在OrderViewModels 内传播PropertyChanged 事件并将它们聚合成一个单独的事件。当我想这样做时,我使用了一个名为 ItemObservableCollection 的类:

public sealed class ItemObservableCollection<T> : ObservableCollection<T>
    where T : INotifyPropertyChanged
{
    public event EventHandler<ItemPropertyChangedEventArgs<T>> ItemPropertyChanged;

    protected override void InsertItem(int index, T item)
    {
        base.InsertItem(index, item);
        item.PropertyChanged += item_PropertyChanged;
    }

    protected override void RemoveItem(int index)
    {
        var item= this[index];
        base.RemoveItem(index);
        item.PropertyChanged -= item_PropertyChanged;
    }

    protected override void ClearItems()
    {
        foreach (var item in this)
        {
            item.PropertyChanged -= item_PropertyChanged;
        }

        base.ClearItems();
    }

    protected override void SetItem(int index, T item)
    {
        var oldItem = this[index];
        oldItem.PropertyChanged -= item_PropertyChanged;
        base.SetItem(index, item);
        item.PropertyChanged += item_PropertyChanged;
    }

    private void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        OnItemPropertyChanged((T)sender, e.PropertyName);
    }

    private void OnItemPropertyChanged(T item, string propertyName)
    {
        var handler = this.ItemPropertyChanged;

        if (handler != null)
        {
             handler(this, new ItemPropertyChangedEventArgs<T>(item, propertyName));
        }
    }
}

public sealed class ItemPropertyChangedEventArgs<T> : EventArgs
{
    private readonly T _item;
    private readonly string _propertyName;

    public ItemPropertyChangedEventArgs(T item, string propertyName)
    {
        _item = item;
        _propertyName = propertyName;
    }

    public T Item
    {
        get { return _item; }
    }

    public string PropertyName
    {
        get { return _propertyName; }
    }
}

我可以这样使用它:

var orders = new ItemObservableCollection<OrderViewModel>();
orders.CollectionChanged   += OnOrdersChanged;
orders.ItemPropertyChanged += OnOrderChanged;

【讨论】:

  • 嗨,感谢您的回复。只是试图使其工作并编译。我缺少“ItemPropertyChanged.Raise”和 ItemPropertyChangedEventArgs 类。你介意把它贴出来让我试试。非常感谢。我刚刚碰到 ListCollectionView 是另一种实现相同的方法吗?
  • 不错。我正在更改我的所有代码以使用您ItemPropertyChangedEventArgs 设计。以前我只是在属性名称前加上Item.,因为它冒泡了,但这提供了一个更好的解决方案。
  • 您的 ItemPropertyChangedEventArgs 是什么样的。当您说 Raise 时,您的意思是 Invoke 吗?感谢您的帮助
  • 我也很想知道 ItemPropertyChangedEventArgs 的样子... C# 在 ItemPropertyChanged.Raise(...) 行上给了我错误,因为它不知道 Raise 是什么,也不知道什么是 ItemPropertyChangedEventArgs。
【解决方案2】:

System.ComponentModel.BindingList&lt;Type&gt; 提供与ObservableCollection&lt;Type&gt; 相同的功能并正确处理PropertyChanged 事件。

最好的问候

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-26
    • 1970-01-01
    • 2021-06-03
    • 2015-10-19
    • 2018-02-01
    • 2010-10-17
    • 2016-07-17
    • 2013-09-24
    相关资源
    最近更新 更多