1

DockPanel にネストされた DataGrid があります。DockPanel はデータ コンテキストとして機能します。

DockPanel1.DataContext = GetData();

GetData() メソッドは ObservableCollection を返します。

ObservableCollection は、DataGrid だけでなく、DockPanel にネストされたいくつかのテキスト ボックスでも変更できます。また、DataView を使用してコレクションをナビゲートします。

コレクションが変更されたかどうかを検出し、ユーザーがデータを保存せずにアプリケーションを閉じようとしたときに警告したいと思います。

使用できる組み込みのメカニズムはありますか (コレクションまたはビューの「IsDirty」フラグのようなもの)? そうでない場合は、すべてのコントロールを監視し、変更を手動で検出する必要があると思います。

ありがとう、レシェク

4

2 に答える 2

3

コレクション自体の変更を検出するには、CollectionChangedハンドラーをアタッチする必要があります。コレクションに含まれるオブジェクトの変更も検出する必要がある場合は、すべてのオブジェクトにPropertyChangedハンドラーをアタッチする必要があります(オブジェクトがINotifyPropertyChangedを実装している場合)。

実装は基本的に次のようになります。

var collection = GetData();
collection.CollectionChanged += OnCollectionChanged;

...

private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    switch (e.Action)
    {
        case NotifyCollectionChangedAction.Add:
            AddPropertyChanged(e.NewItems);
            break;
        case NotifyCollectionChangedAction.Remove:
            RemovePropertyChanged(e.OldItems);
            break;
        case NotifyCollectionChangedAction.Replace:
        case NotifyCollectionChangedAction.Reset:
            RemovePropertyChanged(e.OldItems);
            AddPropertyChanged(e.NewItems);
            break;
    }

    ...
}

private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
    ...
}

private void AddPropertyChanged(IEnumerable items)
{
    if (items != null)
    {
        foreach (var obj in items.OfType<INotifyPropertyChanged>())
        {
            obj.PropertyChanged += OnPropertyChanged;
        }
    }
}

private void RemovePropertyChanged(IEnumerable items)
{
    if (items != null)
    {
        foreach (var obj in items.OfType<INotifyPropertyChanged>())
        {
            obj.PropertyChanged -= OnPropertyChanged;
        }
    }
}
于 2012-12-18T15:56:47.947 に答える
1

上記のクレメンスの答えを少し詳しく説明するために、これらのイベント(コレクションおよび含まれるアイテム)を使用して、説明したような IsDirty フラグを実装する簡単な方法を次に示します。

public class DirtyCollection<T> : ObservableCollection<T> where T : INotifyPropertyChanged
{
    private bool isDirty = false;

    public bool IsDirty
    {
        get { return this.isDirty; }
    }

    public void Clean()
    {
        this.isDirty = false;
    }

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        // We aren't concerned with how the collection changed, just that it did.
        this.isDirty = true;

        // But we do need to add the handlers to detect property changes on each item.
        switch (e.Action)
        {
            case NotifyCollectionChangedAction.Add:
                this.AddPropertyChanged(e.NewItems);
                break;

            case NotifyCollectionChangedAction.Remove:
                this.RemovePropertyChanged(e.OldItems);
                break;

            case NotifyCollectionChangedAction.Replace:
            case NotifyCollectionChangedAction.Reset:
                this.RemovePropertyChanged(e.OldItems);
                this.AddPropertyChanged(e.NewItems);
                break;
        }

        base.OnCollectionChanged(e);
    }

    private void AddPropertyChanged(IEnumerable items)
    {
        if (items != null)
        {
            foreach (var obj in items.OfType<INotifyPropertyChanged>())
            {
                obj.PropertyChanged += OnItemPropertyChanged;
            }
        }
    }

    private void RemovePropertyChanged(IEnumerable items)
    {
        if (items != null)
        {
            foreach (var obj in items.OfType<INotifyPropertyChanged>())
            {
                obj.PropertyChanged -= OnItemPropertyChanged;
            }
        }
    }

    private void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        // A property of a contained item has changed.
        this.isDirty = true;
    }
}

コードはかなり自明である必要があります。

もちろん、「where T : INotifyPropertyChanged」を削除して、そのインターフェイスを実装していないオブジェクトをコレクションに格納できるようにすることもできますが、そのインターフェイスがない場合と同様に、オブジェクトのプロパティの変更が通知されません。 、彼らはあなたにそれらを通知することはできません。

また、コレクションがダーティであることだけでなく、その方法も追跡したい場合は、イベント引数で渡された情報を記録する OnCollectionChanged および OnItemPropertyChanged のいくつかの追加が適切に行われます。

于 2012-12-18T16:51:22.433 に答える