2016-06-30 8 views
2

これと同様の質問に対するいくつかの回答を見てきましたが、私が考えている特定のパラダイムがC#でも可能であるかどうかは疑問でした。まず、私は問題をレイアウトします:簡単にWPFのUIに通知を伝播

私はC#で開発しているMVVMアプリケーションを持っています。モデルにはプロパティが変更されており、モデル内で単一のプロパティが変更されると、ビューモデルの複数のプロパティに影響することがあります。したがって、ビュー・モデルはモデルの変更をリッスンします。ビューはビューモデルの変更をリッスンします。それだけで厄介そうなので

private void OnModelPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) 
{ 
    string prop_name = e.PropertyName; 
    if (prop_name.Equals("some_property_on_the_model")) 
    { 
     NotifyPropertyChanged("some_property_on_the_view_model"); 
     NotifyPropertyChanged("some_property_on_the_view_model"); 
     NotifyPropertyChanged("some_property_on_the_view_model"); 
     NotifyPropertyChanged("some_property_on_the_view_model"); 
     NotifyPropertyChanged("some_property_on_the_view_model"); 
    } 
    else if (...) 
    { 
     ... etc ... 
    } 
} 

これは厄介な取得します。私の見解・モデルでは

は、私はこのようになりますいくつかのコードを取得してしまいます。ビューモデルに新しいプロパティを追加した後でこの関数を編集することを忘れた場合、バグが発生しやすくなります。

ここで私はのようにのようにしていますが、これが可能かどうかはわかりません。だから私は可能かどうかを理解するのを手伝っていただきたいと思います。

C#の「属性」機能を使用してプロパティの変更された伝播を処理することができれば、本当にクールです。

そのため、おそらくこのような何か:

[ListenToModelProperty("some_property_on_the_model")] 
[OnPropertyChanged("MyButtonVisibility")] 
public Visibility MyButtonVisibility 
{ 
    get 
    { 
     if (model.some_property_on_the_model == true) 
     { 
      return Visibility.Visible; 
     } 
     else 
     { 
      return Visibility.Hidden; 
     } 
    } 
} 

private void OnModelPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) 
{ 
    prop_name = e.PropertyName; 

    foreach (var property in view_model) 
    { 
     var attributes = property.GetCustomAttributes(typeof(ListenToModelPropertyAttribute)); 
     var descriptions = attributes.Select(x => x.Description); 
     if (descriptions.Contains(prop_name)) 
     { 
      notification_to_make = property.GetCustomAttributes(typeof(OnPropertyChangedAttribute)); 
      string notification_string = notification_to_make[0].Description; 
      NotifyPropertyChanged(notification_string); 
     } 
    } 
} 

は、上記のコードは、実際のコードであることを意味するものではないことに注意してください。それは間違いなくコンパイルされず、動作しません。しかし、私は上記のようなものがC#で可能かどうかを見たいと思います。属性を使ってこれを行うことは可能ですか?それとも、このようなことを可能にするライブラリがありますか?

+0

これはしばしば私たちのチームの頭痛です。 Fody PropertyChangedには、この問題を少しずつ違う方法で解決しようとしています。 https://github.com/Fody/PropertyChanged。私は個人的には生産でそれを試していない! – Rowbear

答えて

1

私はそれを行う方法を考え出しました!それはかなり簡単です。ここで関連するコードを投稿し、関心のある人は、私が作成したこのgithubリポジトリですべてのコードを見つけることができます:https://github.com/davepruitt/model-subscribe

まず、私はカスタム属性クラスを作成しました。これは、コンストラクタのパラメータとして文字列の配列をとる単純なクラスです。これにより、モデルの複数のプロパティーを変更のために聴くことができます。これは次のようになります。

using System; 
using System.Collections.Generic; 

namespace TestPropagationOfPropertyChanges 
{ 
    [AttributeUsage(AttributeTargets.All)] 
    public class ListenForModelPropertyChangedAttribute : System.Attribute 
    { 
     public List<string> ModelPropertyNames = new List<string>(); 

     public ListenForModelPropertyChangedAttribute (string [] propertyNames) 
     { 
      ModelPropertyNames.AddRange (propertyNames); 
     } 
    } 
} 

私のモデルを作成しました。簡単にするために、2つのプロパティのみが含まれています。彼らは、「ファースト・ネーム」と「姓」を格納した文字列です:

using System; 
using System.ComponentModel; 

namespace TestPropagationOfPropertyChanges 
{ 
    public class Model : NotifyPropertyChangedObject 
    { 
     #region Constructors 

     public Model() 
     { 
     } 

     #endregion 

     #region Private data members 

     private string _first = string.Empty; 
     private string _last = string.Empty; 

     #endregion 

     #region Public properties 

     public string FirstName 
     { 
      get 
      { 
       return _first; 
      } 
      set 
      { 
       _first = value; 
       NotifyPropertyChanged ("FirstName"); 
      } 
     } 

     public string LastName 
     { 
      get 
      { 
       return _last; 
      } 
      set 
      { 
       _last = value; 
       NotifyPropertyChanged ("LastName"); 
      } 
     } 

     #endregion 
    } 
} 

ビュー・モデルは、この場合には、「フルネーム」プロパティがあります。だから、モデルのファーストネームやラストネームに起こった変更を聴き、そのいずれかの変更に反応したいと思っています。私はこれがこの種のシステムが使用される最良の「現実の」シナリオではないことを認識していますが、その概念を説明するのに役立ちます。ビューモデルの最初の部分は次のとおりです。

using System; 

namespace TestPropagationOfPropertyChanges 
{ 
    public class ViewModel : NotifyPropertyChangedObject 
    { 
     #region Private data members 

     //This is public for testing purposes 
     public Model _model = new Model(); 

     #endregion 

     #region Constructors 

     public ViewModel() 
     { 
      _model.PropertyChanged += ReactToModelPropertyChanged; 
     } 

     #endregion 

     #region Properties 

     [ListenForModelPropertyChangedAttribute(new string [] {"FirstName", "LastName"})] 
     public string FullName 
     { 
      get 
      { 
       return _model.FirstName + _model.LastName; 
      } 
     } 

最後に、ビューモデルはモデルの変更に対応するメソッドで終了します。通常、大規模で複雑なアプリケーションでは、このメソッドにNotifyPropertyChangedを多数呼び出す大規模なif-elseステートメントを含めることができます。代わりに、ビューモデルのプロパティを繰り返して、変更されたモデルのプロパティをどのビューに登録するかを確認するだけです。以下を参照してください:

全体的には、それはうまく機能し、私が必要としていたものです。このコードは、関心のある人にとってさらに機能的になるように容易に拡張することができます。