2

これがよく議論されていることは知っていますが、私はこれを機能させることができませんでした。

View - ViewModel - WPF にモデルがあります。Model のプロパティが変更されたという情報を渡す必要があります。最終的にビューで情報を処理する必要があります。ここでは、View から ViewModel へのデータ バインディングがないことに注意してください。

ViewModelには、モデル オブジェクトのコレクションがあります。

Public Property Items as ObservableCollection(Of Item)

モデルは次のとおりです。

Public Class Item
    Public Property Name as String
End Class

私がしたいのは、ViewModel のコレクション「Items」内のアイテムのいずれかでプロパティ「Name」が変更されるたびに実行される View コード ビハインド (以下を参照) でプロシージャを実行することです。

ビュー:

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」が正しい方法かどうかわかりません。「PropertyChanged は T のイベントではありません」という item.PropertyChanged を取得します。
これで私を助けてくれませんか。そうでなければ、私はコンセプト/アイデアを得ました。

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
4

1 に答える 1

2

モデル クラスがインターフェイスを正しく実装している場合、イベント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

または、それらを次のように追加しますItems

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

これを行う必要がある場合は、ObservableCollection<T>クラスを拡張し、Addメソッドをオーバーライドしてハンドラーをアタッチ (およびコンストラクターから呼び出し) し、Removeメソッドをオーバーライドしてハンドラーを削除します。


更新 2 >>>

私の拡張ObservableCollection<T>クラスは長すぎてここに表示できませんが、最初にその一部を示します... 削除しすぎていないことと、すべてがまだ機能していることを願っています... いずれにせよ、あなたはあなただと思いますアイデアを得るでしょう:

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;
于 2013-10-21T11:26:55.767 に答える