2009-05-09 15 views
16

なぜWPFはオブジェクトのプロパティにバインドをサポートしますが、フィールドはバインドできませんか?

:そうのような

public class ServiceViewModel : ViewModel 
{ 
    public StatusInfo CurrentStatus 
    { 
     get{ return _currentStatus; } 
     set 
     { 
      _currentStatus = value; 
      OnPropertyChanged(() => CurrentStatus); 
     } 
    }  
} 

とXAML:私はこのようなビューモデルでプロパティを公開

[DataContract] 
public struct StatusInfo 
{ 
    [DataMember] public int Total; 
    [DataMember] public string Authority; 
} 
... 
public StatusInfo GetStatus() { ... } 

私はそうのような構造体を経由してステータスの更新の周囲を通過するWCFサービスを持っています私はアプリを実行すると

<TextBox Text="{Binding CurrentStatus.Total}" /> 

私は総資産が見つからないことを示す出力ウィンドウにエラーが表示されます。私はチェックしてダブルチェックし、正しくタイプしました。それは、エラーは、特に「プロパティが」が見つかりませんことを示していることを私に起こりました。だから、構造体にプロパティを追加するだけで正常に動作しました。しかし、これはWPFのフィールドに結合する一方通行を扱うことができないように私には奇妙に思えます。文法的にあなたは、コード内でそれらを同じにアクセスし、それだけでStatusInfo構造体用のカスタムビューモデルを作成する必要が愚かなようです。私はWPFバインディングについて何か不足していますか?あなたは、フィールドにバインドするか、唯一の方法を結合性であることはできますか?

答えて

21

バインド一般にはフィールドには対応しません。ほとんどのバインディングは、ComponentModel PropertyDescriptorモデルに部分的に基づいています(デフォルトではプロパティで動作します)。これにより、通知、検証などが可能になります(どれもフィールドで動作しません)。

私が入ることができる以上の理由から、パブリックフィールドは悪い考えです。それらはプロパティ、事実でなければなりません。同様に、変更可能な構造体は非常にという悪い考えです。特に、予期せぬデータ損失(通常は変更可能な構造体に関連付けられています)から保護します。これはクラスでなければなりません:

[DataContract] 
public class StatusInfo 
{ 
    [DataMember] public int Total {get;set;} 
    [DataMember] public string Authority {get;set;} 
} 

これは、あなたが思うように動作するようになりました。あなたはそれが不変構造体になりたい場合は、それはOKになります(ただし、データ・バインディングは、一方向のみ、当然のことでしょう):

[DataContract] 
public struct StatusInfo 
{ 
    [DataMember] public int Total {get;private set;} 
    [DataMember] public string Authority {get;private set;} 

    public StatusInfo(int total, string authority) : this() { 
     Total = total; 
     Authority = authority; 
    } 
} 

しかし、私はこれは構造体である、なぜ最初の質問は、希望最初は非常に珍しい .NET言語で構造体を記述する。 WCFの "mex"プロキシレイヤーは、(アセンブリの共有を使用しない限り)それをコンシューマのクラスとして作成することに注意してください。 「なぜ使用の構造体」返信(「不明(グーグル)」)への答えで


それは私の質問への回答である場合には、それは多くの点で間違っています。最初に、値タイプを変数としてスタック上に(最初に)割り当てます。それらがヒープ(配列/リストなど)にプッシュされると、オブジェクトヘッダーと参照の小さなビットであるクラスとのオーバーヘッドに大きな違いはありません。構造体は常にである必要があります。複数のフィールドを持つものはオーバーサイズになり、あなたのスタックを殺すか、またはblittingによって遅くなるでしょう。さらに、構造体は不変でなければなりません。実際にはがあなたのしていることを知っていなければなりません。

オブジェクトを表現するものは、ほとんどすべてがイマージュでなければなりません。

データベースを操作している場合、構造体対クラスの速度は、プロセス外やおそらくネットワークを経由する場合に比べて問題になりません。たとえ少し遅いとしても、オブジェクトをオブジェクトとして扱うという点に比べて何の意味もありません。 1Mオブジェクトに対するいくつかの指標として

:下記に基づいて

struct/field: 50ms 
class/property: 229ms 

(速度差は、オブジェクトの割り当てではなく、プロパティVS分野です)。だから約5倍遅いが、まだ非常に、非常に迅速。これはあなたのボトルネックになることはないので、これを早めに最適化しないでください!

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
struct MyStruct 
{ 
    public int Id; 
    public string Name; 
    public DateTime DateOfBirth; 
    public string Comment; 
} 
class MyClass 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public DateTime DateOfBirth { get; set; } 
    public string Comment { get; set; } 
} 
static class Program 
{ 
    static void Main() 
    { 
     DateTime dob = DateTime.Today; 
     const int SIZE = 1000000; 
     Stopwatch watch = Stopwatch.StartNew(); 
     List<MyStruct> s = new List<MyStruct>(SIZE); 
     for (int i = 0; i < SIZE; i++) 
     { 
      s.Add(new MyStruct { Comment = "abc", DateOfBirth = dob, 
        Id = 123, Name = "def" }); 
     } 
     watch.Stop(); 
     Console.WriteLine("struct/field: " 
        + watch.ElapsedMilliseconds + "ms"); 

     watch = Stopwatch.StartNew(); 
     List<MyClass> c = new List<MyClass>(SIZE); 
     for (int i = 0; i < SIZE; i++) 
     { 
      c.Add(new MyClass { Comment = "abc", DateOfBirth = dob, 
        Id = 123, Name = "def" }); 
     } 
     watch.Stop(); 
     Console.WriteLine("class/property: " 
        + watch.ElapsedMilliseconds + "ms"); 
     Console.ReadLine(); 
    } 
} 
+4

C++プログラマーとして、私は上記のコメントを非常に理解しにくいと感じます。私はまた別の結論に達するようです。たとえば、「ゆっくりだが、まだ非常に速い」と言う。それに対して、「構造体の使用は約5倍高速ですが、非常に遅いです。」 –

+7

@ダニエルの怒り、ここで私たちは再び "C++はあらゆるものよりも速く、いつも使われなければならない"(しばらく)。幅広い種類のアプリケーションでは、明らかに差がありません。 –

+0

私はC++が速いとは決して言わなかった!そのような結論は、あなたには深刻な先入観(あるいは誤解かもしれない)があることを示しました。 「C++は高速であるかもしれませんが、これは重要ではありませんが、C++ではそれを正しく取得するのが容易になります。これは重要です。あるいは、あなたが私の議論を支持すると言ったことをちょうど誤って解釈したのかもしれません。 –

0

彼らはプロパティのみをサポートし、なぜ私は推測することができます:可変フィールド(probably to safeguard binary compatibility)を露出しないように決して.NETフレームワークにおける普遍的な条約のようですおそらくので、彼らは何とかすべてのプログラマが同じに従うことを期待コンベンション。

また、フィールドとプロパティは同じ構文でアクセスされますが、データバインディングはリフレクションを使用するため、プロパティにアクセスするよりもフィールドにアクセスするためにリフレクションを別々に使用する必要があります。

関連する問題