2009-03-24 8 views
1

WPFのMVVMパターンのViewModel部分をWPFアセンブリを参照せずに実装したいと思います。問題のある部分はコマンドルーティングで、コマンドバインドが機能するようにViewModelsにタイプICommandのプロパティを実装する必要があります。.NETクラスへのプロパティのポストコンパイル

ここではICommandを避け、単にプロパティーをobjectと宣言します。すべてがまだ機能しているので、それだけです。しかし、私を悩ますものは、をまだ宣言しなければなりません。彼らがボイラープレートコードのように感じるので、私は本当にしたくありません。

私のviewmodelsは現在、次のようになります。

public class HelloWorldViewModel : ViewModel 
{ 
    [BoundProperty] 
    public string Name { get; set; } 

    [CommandHandler("SayHello")] 
    public bool CanSayHello() 
    { 
     return Name != "" && Name != null; 
    } 

    [CommandHandler("SayHello")] 
    public void SayHello() 
    { 
     View.ShowMessage("Hello, {0}!", Name); 
    } 

    public object SayHello { get; private set; } 
} 

BoundPropertyAttributeが本当にプロパティに自分自身を挿入側面ている間CommandHandlerAttributeは、(ActionとオプションFunc<bool>)コマンドハンドラの実行時の発見を可能にしますセッターとINotifyPropertyChangedを呼び出します。私はコンパイル時ILウィーバーを使用してこれを行います。

理想的には、最後の行(SayHelloプロパティ)も暗黙的にしたいと考えています。それがWPFの要件でなければ、ソースにそこに存在することには意味がありません。

だから、当然、私は、プロパティのポストコンパイルを作成するクラスに必要なILを注入するCommandHandlerAttribute側面を使用して考え、基本的です。これは非常に難しいですが、優れたILウィーバー(例:PostSharpなど)は、それをより簡単にするために長い道を行くことができます。

私はこの旅に着手する前に、皆さんが私のアプローチについて考えていることを聞きたいと思います。それは健全ですか?より良い方法がありますか?どのように/あなたはそれをやりますか?

答えて

3

私にとってこれはあまりにも賢いようです。あまりにも多くの "魔法"が起こっている。特に、私はあなたのCommandHandlerAttributeの魔法の文字列および他の側面を嫌います。つまり、もし私がこのルートを下っていくのであれば、私はEventAggregatorのようなものをコマンドのために使うでしょう。 IOW、SayHelloはあなたのViewModelには全く存在しません。 SayHell()とCanSayHello()へのコマンドバインディングを作成する魔法は、代わりにコマンドをグローバルCommandAggregatorで見つけることができます。このために魔法の文字列を使用している限り、CommandAggregatorのコマンドは遅れて作成される可能性があります。したがって、 "ボイラープレート"のコーディングは必要ありません。残されているのは、ICommandSourceでコマンドを指定するためのXAMLの魔法(マークアップ拡張)を作成することだけです。

<Button Command="{my:AggregateCommand SayHello}"/> 
0

私の個人的な意見はこれは興味深いことですが、一般的には避けています。

ボイラープレートコード(またはボイラープレートコードのようなコード)を避けることは、結果をもたらします。物事を絶えず再タイピングしているわけではないので、良いアイデアのように思えるかもしれませんが、長期的には、読みにくく理解しやすくなっています。

個人的には、ボイラープレートのコードを挿入するための良いコードテンプレートを設定して、リージョンでラップしてソースコードに隠すことができます。ボイラープレートを使ってファイルを書き込むのにかかる時間は30秒です(私にとっては2時間、2年後にはコードを理解しようとしています)、それより悪いことに、2週間の誰か他にも2年後に自分のコードを理解しようとしています....

1

プリズムで遊んでからしばらく経ちましたが、MVVMのように見える前に、私はまだ考えている戦略を考え出しましたいくつかの妥当性:

私はリフレクションに基づいてICommandインターフェイスの実装を作成しました。コンストラクタは、ターゲットオブジェクトと操作名を受け入れました。リフレクションを使用して、コードは名前「[操作]」、名前が「Can [操作]」または「[操作]が有効」の名前のプロパティまたはメソッド、名前が「Can [操作]が変更された」イベントまたは「[操作]有効に変更しました。最初のものだけが必要でしたが、反映されたメソッド/プロパティ/イベントは、ICommandインターフェイスのかなり基本的な実装に配線されていました。

次に、以前のクラスのインスタンスを作成し、変換する値をターゲットオブジェクトとして渡すIValueConverterのインプリメンテーションを作成し、コンバーターのパラメーターを操作名として渡しました。

私は、例えば、ボタンのCommandプロパティを(変換器の指定と同時に)操作のソースに直接バインドし、ButtonのCommandParameterプロパティを操作の名前に設定することができました。このようにして、私は宣言的なコマンドバインディングを持っています。

+0

「魔法」メソッドとプロパティ名でリフレクションを使用するのは嫌です。私は過去にしばしば見つかったメソッドの名前を変更し、予期せぬUIの問題がコンパイラなしで動作しなくなり、エラーが発生しました。しかし、私はあなたの基本的なデザインが好きです、ワイヤーアップを行うラムダ式はどうですか? –

+0

私はたくさんのラムダの考えが好きです。私はまだインタフェースを単純化するので、リフレクションを介して(少なくともデフォルトでは) "有効にされた"プロパティ/イベントを発見したいかもしれません。 –

0

あなたの場合の最善の方法は、私が思うところではプロキシまたはデコレータのパターンです。実行時にUI/WPFスタッフメンバーでラップ/デコレートされた低レベルのエンティティを使用できます。これは、時間を節約し、フレームワーク、注入などを気にしない、最も簡単で効率的な方法です。

エンティティを適切なデコレータでラップするには、小さなインフラストラクチャを設計する必要があります。

2

私はこれが実装されました、そしてそれが役立つかを確認するためにあなたをアドバイス:

"魔法のようなもの" 楽INotifyPropertyChangedの

[http://visualstudiogallery.msdn.microsoft.com/ d5cd6aa1-57a5-4aaa-a2be-969c6db7f88a] [1]

つのプロパティに追加するための例として:

[Magic] 
public string Name { get { return _name; } set { _name = value; } } 
string _name; 

これをすべてのクラスプロパティに追加する別の例:

[Magic] 
public class MyViewModel: INotifyPropertyChanged 
{ 
    public string Name { get; set; } 
    public string LastName { get; set; } 
    ..... 
}