3

プロパティが変更されたかどうかを確認するための「簡単な」/良い方法があるかどうか疑問に思いました。下の階層のように、Child.Nameが変更されたとき(isDirty)知りたいです。

GrantParent
- Parent
-- Child

私の現在の状況では、モデルをナビゲートして、何かが変更されたかどうかを確認する必要があります。

ps:私はを使用してIChangeTrackingいます。

シリアル化されたオブジェクトのハッシュをキャッシュすることを考えています。(遅すぎる?)

または、grantparentに到達するまで親を呼び出すchangedeventを作成します。(おしゃべり?)

  public class Parent: BaseEntity
  {
    private Child _child;
    public Child Child
    {
      get { return _child; }
      set { _child = value; OnPropertyChanged("Child"); }
    }
  }

  public class Child : BaseEntity
  {
    private  int _id;
    public int Id {
      get { return _id; }
      set { _id = value; OnPropertyChanged("Id"); }
    }
  }



 [DataContract]
  [Serializable]
  public abstract class BaseEntity : INotifyPropertyChanged
  {
    protected BaseEntity()
    {
      PropertyChanged += PropertyChangedEventHandler;
    }

    private void PropertyChangedEventHandler(object sender, PropertyChangedEventArgs e)
    {
      if (e != null && !String.Equals(e.PropertyName, "IsChanged", StringComparison.Ordinal))
      {
        this.IsChanged = true;
      }
    }

    protected void OnPropertyChanged<T>(Expression<Func<T>> property)
    {
      MemberExpression me = property.Body as MemberExpression;
      if (me == null || me.Expression != property.Parameters[0]
            || me.Member.MemberType != MemberTypes.Property)
      {
        throw new InvalidOperationException(
            "Now tell me about the property");
      }
      var handler = PropertyChanged;
      if (handler != null) handler(this,
        new PropertyChangedEventArgs(me.Member.Name));
    }

    [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public bool IsChanged
    {
      get
      {
        lock (_notifyingObjectIsChangedSyncRoot)
        {
          return _notifyingObjectIsChanged;
        }
      }

      protected set
      {
        lock (_notifyingObjectIsChangedSyncRoot)
        {
          if (!Boolean.Equals(_notifyingObjectIsChanged, value))
          {
            _notifyingObjectIsChanged = value;

            if (IsDirtyChanged != null)
              IsDirtyChanged();

            this.OnPropertyChanged("IsChanged");
          }
        }
      }
    }

    private bool _notifyingObjectIsChanged;
    private readonly object _notifyingObjectIsChangedSyncRoot = new Object();

    public void AcceptChanges()
    {
      this.IsChanged = false;
    }
  }

結局、私はすでに使用したXMLシリアライザーからのXMLモデルの比較を使用しました。私は、1秒に1回(またはそれくらい)の即時の変化検出を「必要」としませんでした。ここで、前回の保存以降に使用していたものでXMLモデルを確認します。

4

2 に答える 2

3

各プロパティでそれ自体を追跡し、変更されたプロパティを示す情報を保存するか、アイテムが変更されたときにイベントを発生させる必要があります。

基本的に、各プロパティには次のようなロジックがあります。

public class MyClass : INotifyPropertyChanged
{
    private int _value;
    public int Value
    {
        get
        {
            return _value;
        }
        set
        {
            _value = value;
            PropertyChanged(this, new PropertyChangedEventArgs("Value"));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

これにより、PropertyChangedイベントにイベントハンドラーを追加して、プロパティが変更されたときにコードが起動されるようにすることができます。

于 2012-10-26T14:23:45.740 に答える
2

私は最近、すべてのノード/リーフにnode.Modifiedプロパティを実装させ、のINotifyPropertyChanged状態変化を発生させるために使用するプロジェクトに取り組みましたnode.Modified。次に、すべての親が子供のプロパティの変更をサブスクライブし、trueに設定された場合node.Modifiedは、自分のプロパティをtrueに設定node.Modifiedします。

あなたが言うように、それは少しおしゃべりですが、毎秒何千もの変更が見られず、階層が3レベルしかないため、パフォーマンスのボトルネックにはなりません。

簡単なサンプルを次に示します。

class Node : INotifyPropertyChanged
{

    public Node()
    {
        Children = new List<Node>();
    }
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string name)
    {
        var temp = PropertyChanged;
        if (temp != null)
            temp(this, new PropertyChangedEventArgs(name));
    }

    public IList<Node> Children { get; private set; }
    public void AddChild(Node node)
    {
        node.PropertyChanged += ChildPropertyChanged;
        Children.Add(node);
    }

    void ChildPropertyChanged(object sender, PropertyChangedEventArgs args)
    {
        if (args.PropertyName == "Modified")
            Modified |= ((Node)sender).Modified;
    }

    bool _modified = false; 
    public bool Modified 
    {
        get { return _modified; } 
        set 
        {
            if (_modified != value)
            {
                _modified = value;
                OnPropertyChanged("Modified");
            }

        } 
    }

編集:一種のメッセージバスを使用する別の方法があります。完璧ではないかもしれませんが、それは問題への別のアプローチなので、それも共有します。私はすぐに些細なMsgバスをハックしました...

static class Bus<T>
{

    public static Dictionary<object, Action<object, T>> Subscriptions = new Dictionary<object, Action<object, T>>();
    public static void Raise(object sender, T message)
    {
        foreach (Action<object, T> action in Subscriptions.Values)
        {
            action(sender, message);
        }
    }

    public static void Subscribe(object subscriber, Action<object, T> action)
    {
        Subscriptions[subscriber] = action;
    }

    public static void Unsubscribe(object subscriber)
    {
        if (Subscriptions.ContainsKey(subscriber))
            Subscriptions.Remove(subscriber);
    }

}

public class WasModified { }

そして変更されたノード

class Node
{

    public Node()
    {
        Children = new List<Node>();
    }

    public IList<Node> Children { get; private set; }

    bool _modified = false; 
    public bool Modified 
    {
        get { return _modified; } 
        set 
        {
            if (_modified != value)
            {
                _modified = value;

                if (_modified == true)
                    Bus<WasModified>.Raise(this, new WasModified());
            }

        } 
    }
}

最後に、それは使用です。

    static void Main(string[] args)
    {

        Node parent = new Node();
        Bus<WasModified>.Subscribe(parent, (s,a)=> parent.Modified = true);
        Node child = new Node();
        Node gchild = new Node();
        parent.Children.Add(child);
        parent.Children.Add(gchild);
        gchild.Modified = true;
        Console.WriteLine(parent.Modified);


        Console.ReadLine();
    }

メッセージバスは親オブジェクトにバブルアップする必要はなく、Modifiedが変更されたかどうかを確認するたびに親オブジェクトに再帰する必要はないので、おそらくそれがあなたが探しているものです。

于 2012-10-26T14:35:32.177 に答える