Wpf 无数据绑定时将propertychanged从模型传递到视图

Wpf 无数据绑定时将propertychanged从模型传递到视图,wpf,vb.net,mvvm,propertychanged,Wpf,Vb.net,Mvvm,Propertychanged,我知道这已经被讨论了很多,但我一直无法让它工作 我在WPF中有一个View-ViewModel-Model。 我需要传递模型中的属性已更改的信息。我需要最终在视图中处理这些信息。 请注意,这里从视图到视图模型没有数据绑定 在ViewModel中,我有一组模型对象: Public Property Items as ObservableCollection(Of Item) 模型是: 我要做的是在视图代码隐藏(见下文)中运行一个过程,该过程在ViewModel中集合“items”中的任何项的属性

我知道这已经被讨论了很多,但我一直无法让它工作

我在WPF中有一个View-ViewModel-Model。 我需要传递模型中的属性已更改的信息。我需要最终在视图中处理这些信息。 请注意,这里从视图到视图模型没有数据绑定

在ViewModel中,我有一组模型对象:

Public Property Items as ObservableCollection(Of Item)
模型是:

我要做的是在视图代码隐藏(见下文)中运行一个过程,该过程在ViewModel中集合“items”中的任何项的属性“Name”发生更改时都会运行

视图:

更新1>>>

为了响应您的自定义类,我尝试将其转换为VB.NET(如下所示),但在这个派生类中重写事件时似乎存在一些问题。不知道“Protected Shadows Event PropertyChanged”是否是正确的方法。我收到item.PropertyChanged,说“PropertyChanged不是T的事件”。
你能帮我做这个吗。否则我就有了这个想法

Public Class BaseCollection(Of T)

Inherits ObservableCollection(Of T)
Implements INotifyPropertyChanged

Protected currentItem As T

Public Sub New(collection As IEnumerable(Of T))
    Me.New()
    For Each item As T In collection
        Add(item)
    Next
End Sub

Public Sub New(collection As ObservableCollection(Of T))
    Me.New(TryCast(collection, IEnumerable(Of T)))
End Sub

Public Sub New(ParamArray collection As T())
    Me.New(TryCast(collection, IEnumerable(Of T)))
End Sub

Public Sub New()
    MyBase.New()
End Sub


Public Shadows Sub Add(item As T)
    AddHandler item.PropertyChanged, AddressOf Item_PropertyChanged
    MyBase.Add(item)
End Sub

Public Overridable Shadows Sub Add(collection As IEnumerable(Of T))
    For Each item As T In collection
        Add(item)
    Next
End Sub

Public Overridable Shadows Sub Add(ParamArray items As T())
    Add(TryCast(items, IEnumerable(Of T)))
End Sub

Protected Overrides Sub InsertItem(index As Integer, item As T)
    If item IsNot Nothing Then
        AddHandler item.PropertyChanged, AddressOf Item_PropertyChanged
        MyBase.InsertItem(index, item)
    End If
End Sub

Protected Overrides Sub ClearItems()
    For Each item As T In Me
        RemoveHandler item.PropertyChanged, AddressOf Item_PropertyChanged
    Next
    MyBase.ClearItems()
End Sub

Public Shadows Function Remove(item As T) As Boolean
    If item Is Nothing Then
        Return False
    End If
    RemoveHandler item.PropertyChanged, AddressOf Item_PropertyChanged
    Return MyBase.Remove(item)
End Function

Public Shadows Sub RemoveAt(index As Integer)
    Dim item As T = Me(index)
    If item IsNot Nothing Then
        RemoveHandler item.PropertyChanged, AddressOf Item_PropertyChanged
    End If
    MyBase.RemoveAt(index)
End Sub


Private Sub Item_PropertyChanged(sender As Object, e As PropertyChangedEventArgs)
    NotifyPropertyChanged(e.PropertyName)
End Sub


#Region "INotifyPropertyChanged Members"

Protected Shadows Event PropertyChanged As PropertyChangedEventHandler

Protected Overridable Sub NotifyPropertyChanged(ParamArray propertyNames As String())
    For Each propertyName As String In propertyNames
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
    Next
End Sub

#End Region


End Class

如果模型类正确实现了
INotifyPropertyChanged
接口,则另一个类可以通过将处理程序附加到
INotifyPropertyChanged.PropertyChanged
事件来侦听属性更改:

YourObject.PropertyChanged += YourObject_PropertyChanged;

...


Private Sub YourObject_PropertyChanged(sender As Object, e As PropertyChangedEventArgs)
    If InlineAssignHelper(e.PropertyName, "Name") Then
        ' Do something with the new Name value here
    End If
End Sub

更新>>>

如果要监视
Items
集合属性中每个项的属性更改,则需要将处理程序附加到每个项。。。你可以这样做:

For Each item As Item In Items
    item.Propertychanged += Item_PropertyChanged
Next
或者当您将它们添加到
项目中时:

For Each item As Item In OtherCollection
    item.Propertychanged += Item_PropertyChanged
    Items.Add(item)
Next
当我需要这样做时,我扩展了
observateCollection
类,覆盖
Add
方法来附加处理程序(并从构造函数调用它们),覆盖
Remove
方法来删除处理程序


更新2>>>

我的扩展的
ObservableCollection
类太长,无法在这里显示,但首先,这里有一些。。。我只是希望我没有删除太多,这一切仍然有效。。。不管怎样,我想你都会想到:

public class BaseCollection<T> : ObservableCollection<T>, INotifyPropertyChanged 
    where T : class, INotifyPropertyChanged
{
    public BaseCollection(IEnumerable<T> collection) : this()
    {
        foreach (T item in collection) Add(item);
    }

    public BaseCollection(ObservableCollection<T> collection) : this(collection as IEnumerable<T>) { }

    public BaseCollection(params T[] collection) : this(collection as IEnumerable<T>) { }

    public BaseCollection() : base() { }

    public new void Add(T item)
    {
        item.PropertyChanged += Item_PropertyChanged;
        base.Add(item);
    }

    public virtual void Add(IEnumerable<T> collection)
    {
        foreach (T item in collection) Add(item);
    }

    public virtual void Add(params T[] items)
    {
        Add(items as IEnumerable<T>);
    }

    protected override void InsertItem(int index, T item)
    {
        if (item != null)
        {
            item.PropertyChanged += Item_PropertyChanged;
            base.InsertItem(index, item);
        }
    }

    protected override void ClearItems()
    {
        foreach (T item in this) item.PropertyChanged -= Item_PropertyChanged;
        base.ClearItems();
    }

    public new bool Remove(T item)
    {
        if (item == null) return false;
        item.PropertyChanged -= Item_PropertyChanged;
        return base.Remove(item);
    }

    public new void RemoveAt(int index)
    {
        T item = this[index];
        if (item != null) item.PropertyChanged -= Item_PropertyChanged;
        base.RemoveAt(index);
    }

    private void Item_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        NotifyPropertyChanged(e.PropertyName);
    }

    #region INotifyPropertyChanged Members

    protected override event PropertyChangedEventHandler PropertyChanged;

    protected virtual void NotifyPropertyChanged(params string[] propertyNames)
    {
        if (PropertyChanged != null)
        {
            foreach (string propertyName in propertyNames) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    #endregion
}

为什么不在视图模型而不是视图中运行您的过程,然后按照WPF的惯例将视图模型属性绑定到视图?在这种情况下,我使用的(第三方)UI组件还不支持数据绑定。所以我现在唯一的选择就是运行代码来更改UI组件。我不认为从ViewModel运行UI代码是一个好主意,或者你能更详细地解释你的想法吗?通常在WPF中,更改数据或对数据更改作出反应不属于UI代码。但是,如果您不能将标准数据绑定与第三方控件一起使用,那么我收回我的建议。相反,我建议您使用一个支持标准数据绑定的合适控件。在这种情况下,不可能找到支持绑定的替代控件。不幸的是,我认为我需要退出WPF(MVVM)标准。如果我能在ViewModel中捕获模型的PropertyChanged事件,这对我来说是可行的。如何注册?模型实现INotifyPropertyChanged yes。如果你看看我原来的邮政编码,你会怎么写?在我的例子中,YourObject是什么?我是否需要为Items ObservableCollection中的每个项目附加处理程序?->无论何时向集合中添加新项目,都会附加处理程序,无论何时删除项目,都会删除处理程序?非常好。是否可以显示您是如何扩展ObservableCollection类的?啊,您可以删除在我的基本集合中执行其他功能的
currentItem
条目,我在本例中删除了该条目。我删除了currentItem。我无法(在您的代码中)获得“item.PropertyChanged+=item\u PropertyChanged;”与VB.NET一起使用,我将其编写为“AddHandler item.PropertyChanged,AddressOf item\u PropertyChanged”->PropertyChanged不是t事件。您能在这里提供帮助吗。
For Each item As Item In OtherCollection
    item.Propertychanged += Item_PropertyChanged
    Items.Add(item)
Next
public class BaseCollection<T> : ObservableCollection<T>, INotifyPropertyChanged 
    where T : class, INotifyPropertyChanged
{
    public BaseCollection(IEnumerable<T> collection) : this()
    {
        foreach (T item in collection) Add(item);
    }

    public BaseCollection(ObservableCollection<T> collection) : this(collection as IEnumerable<T>) { }

    public BaseCollection(params T[] collection) : this(collection as IEnumerable<T>) { }

    public BaseCollection() : base() { }

    public new void Add(T item)
    {
        item.PropertyChanged += Item_PropertyChanged;
        base.Add(item);
    }

    public virtual void Add(IEnumerable<T> collection)
    {
        foreach (T item in collection) Add(item);
    }

    public virtual void Add(params T[] items)
    {
        Add(items as IEnumerable<T>);
    }

    protected override void InsertItem(int index, T item)
    {
        if (item != null)
        {
            item.PropertyChanged += Item_PropertyChanged;
            base.InsertItem(index, item);
        }
    }

    protected override void ClearItems()
    {
        foreach (T item in this) item.PropertyChanged -= Item_PropertyChanged;
        base.ClearItems();
    }

    public new bool Remove(T item)
    {
        if (item == null) return false;
        item.PropertyChanged -= Item_PropertyChanged;
        return base.Remove(item);
    }

    public new void RemoveAt(int index)
    {
        T item = this[index];
        if (item != null) item.PropertyChanged -= Item_PropertyChanged;
        base.RemoveAt(index);
    }

    private void Item_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        NotifyPropertyChanged(e.PropertyName);
    }

    #region INotifyPropertyChanged Members

    protected override event PropertyChangedEventHandler PropertyChanged;

    protected virtual void NotifyPropertyChanged(params string[] propertyNames)
    {
        if (PropertyChanged != null)
        {
            foreach (string propertyName in propertyNames) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    #endregion
}
BaseCollection<YourDataType> items = new BaseCollection<YourDataType>();
items.PropertyChanged += Item_PropertyChanged;