wpf - 没有数据绑定(bind)时将属性更改从模型传递到 View

标签 wpf vb.net mvvm propertychanged

我知道这已经被讨论了很多,但我一直没能让它发挥作用。

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

ViewModel中,我有一个模型对象的集合:

Public Property Items as ObservableCollection(Of Item)

模型是:

Public Class Item
    Public Property Name as String
End Class

我想要做的是在 View 代码隐藏中运行一个过程(见下文),只要 ViewModel 中集合“Items”中的任何项目中的属性“Name”发生更改,该过程就会运行。

查看:

Private Sub NameWasChanged()
    'do something to UI...
    'Item that was changed must be known here as must the new value for the "Name" property
End Sub

更新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接口(interface),另一个类可以通过将处理程序附加到 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

或者当您将它们添加到 Items 时:

For Each item As Item In OtherCollection
    item.Propertychanged += Item_PropertyChanged
    Items.Add(item)
Next

当我需要这样做时,我会扩展 ObservableCollection<T>类并覆盖 Add附加处理程序的方法(并从构造函数调用它们)并覆盖 Remove删除处理程序的方法。


更新2>>>

我的扩展ObservableCollection<T>类(class)太长,无法在这里展示,但为了让您开始,这里是其中的一些...我只是希望我没有删除太多并且它仍然有效...无论哪种方式,我想您都会明白了:

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
}

}

有了这个,您只需添加 PropertyChanged集合的处理程序:

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

关于wpf - 没有数据绑定(bind)时将属性更改从模型传递到 View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19492116/

相关文章:

c# - 在属性网格中扩展自定义对象而不对类进行任何修改?

javascript - window.scrollTo(...) 错误 : Microsoft JScript runtime error: Object expected

c# - IDataErrorInfo 调用绑定(bind)对象而不是 DataContext

c# - WPF 边框形状

vb.net - LINQ to SQL 定义对象标识的成员无法更改

c# - 带有 Dispatcher 的 BackgroundWorker 似乎没有做任何事情

c# - 使用 cal :Message. 附加在 WPF 上下文菜单中的 "No target method found"错误

c# - WPF、MVVM、ICommand 和存储库

c# - 如何从 UserControl 实例创建 DataTemplate?

c# - WPF 图像转换