2011-07-07 6 views
3

WindowsフォームプロジェクトでMVVMパターンのmaster/detailシナリオを実装しようとしています(私は怒っています)。次のビューモデルを考えてみましょう:Windowsフォームのデータバインディングとプロパティパス:NULL可能性を処理する方法は?

public class MasterViewModel 
{ 
    public BindingList<DetailViewModel> Details { get; set; } 

    public DetailViewModel SelectedDetail 
    { 
     get 
     { 
      // 
     } 
     set 
     { 
      // raises SelectedDetailChanged 
     } 
    } 
} 

public class DetailViewModel 
{ 
    public string SubProperty 
    { 
     get 
     { 
      // ... 
     } 
     set 
     { 
      // ... raises SubPropertyChanged 
     } 
    } 
} 

私は次のコードを使用して、テキストボックスにDetailViewModelのサブプロパティをバインドしようとしている(Windowsがサポートされ、プロパティパスをデータバインディングフォーム):

  MasterViewModel masterViewModel; 
      TextBox textBox; 
      // ... 

      Binding binding = new Binding("Text", masterViewModel, "SelectedDetail.SubProperty"); 
      binding.FormattingEnabled = true; 
      binding.DataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged; 
      binding.ControlUpdateMode = ControlUpdateMode.OnPropertyChanged; 

      textBox.DataBindings.Add(binding); 

それは、 WPFのように完璧に動作します... SelectedDetailがnullになるまで(私のロジックでは、SelectedDetailがnullの場合、マスタービューでは何も選択されません)。 SelectedDetailがnullの場合、ArgumentNullException(パラメータ名:component)が取得されます。

「親」プロパティ(ナビゲーションパス内)のNULL可能性を処理する方法はありますか?ここで

は例外スタックトレースです:

in System.ComponentModel.ReflectPropertyDescriptor.AddValueChanged(Object component, EventHandler handler) 
    in System.Windows.Forms.BindToObject.CheckBinding() 
    in System.Windows.Forms.BindToObject.SetBindingManagerBase(BindingManagerBase lManager) 
    in System.Windows.Forms.Binding.SetListManager(BindingManagerBase bindingManagerBase) 
    in System.Windows.Forms.ListManagerBindingsCollection.AddCore(Binding dataBinding) 
    in System.Windows.Forms.BindingsCollection.Add(Binding binding) 
    in System.Windows.Forms.BindingContext.UpdateBinding(BindingContext newBindingContext, Binding binding) 
    in System.Windows.Forms.Control.UpdateBindings() 
    in System.Windows.Forms.Control.OnBindingContextChanged(EventArgs e) 
    in System.Windows.Forms.Control.OnParentBindingContextChanged(EventArgs e) 
    in System.Windows.Forms.Control.OnBindingContextChanged(EventArgs e) 
    in System.Windows.Forms.Control.OnParentBindingContextChanged(EventArgs e) 
    in System.Windows.Forms.Control.OnBindingContextChanged(EventArgs e) 
    in System.Windows.Forms.Control.OnParentBindingContextChanged(EventArgs e) 
    in System.Windows.Forms.Control.OnBindingContextChanged(EventArgs e) 
    in System.Windows.Forms.Control.OnParentBindingContextChanged(EventArgs e) 
    in System.Windows.Forms.Control.OnBindingContextChanged(EventArgs e) 
    in System.Windows.Forms.Control.OnParentBindingContextChanged(EventArgs e) 
    in System.Windows.Forms.Control.OnBindingContextChanged(EventArgs e) 
    in System.Windows.Forms.Control.set_BindingContextInternal(BindingContext value) 
    in System.Windows.Forms.ContainerControl.set_BindingContext(BindingContext value) 
    in System.Windows.Forms.ContainerControl.get_BindingContext() 
    in System.Windows.Forms.Control.get_BindingContextInternal() 
    in System.Windows.Forms.ContainerControl.get_BindingContext() 
    in System.Windows.Forms.Control.get_BindingContextInternal() 
    in System.Windows.Forms.ContainerControl.get_BindingContext() 
    in System.Windows.Forms.Control.get_BindingContextInternal() 
    in System.Windows.Forms.ContainerControl.get_BindingContext() 
    in System.Windows.Forms.Control.get_BindingContextInternal() 
    in System.Windows.Forms.Control.get_BindingContext() 
    in System.Windows.Forms.Control.get_BindingContextInternal() 
    in System.Windows.Forms.Control.get_BindingContext() 
    in System.Windows.Forms.Control.UpdateBindings() 
    in System.Windows.Forms.Control.OnBindingContextChanged(EventArgs e) 
    in System.Windows.Forms.DataGridView.OnBindingContextChanged(EventArgs e) 
    in System.Windows.Forms.Control.OnParentBindingContextChanged(EventArgs e) 
    in System.Windows.Forms.Control.OnBindingContextChanged(EventArgs e) 
    in System.Windows.Forms.Control.OnParentBindingContextChanged(EventArgs e) 
    in System.Windows.Forms.Control.OnBindingContextChanged(EventArgs e) 
    in System.Windows.Forms.ContainerControl.OnCreateControl() 
    in System.Windows.Forms.UserControl.OnCreateControl() 
    in System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible) 
    in System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible) 
    in System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible) 
    in System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible) 
    in System.Windows.Forms.Control.CreateControl() 
    in System.Windows.Forms.Control.WmShowWindow(Message& m) 
    in System.Windows.Forms.Control.WndProc(Message& m) 
    in System.Windows.Forms.ScrollableControl.WndProc(Message& m) 
    in System.Windows.Forms.ContainerControl.WndProc(Message& m) 
    in System.Windows.Forms.Form.WmShowWindow(Message& m) 
    in System.Windows.Forms.Form.WndProc(Message& m) 
... 
    in System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m) 
    in System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) 
    in System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) 
+0

bindingSource1 = new BindingSource(components); bindingSource1.DataMember = "Details"; bindingSource1.DataSource = typeof(MasterViewModel); Binding binding = new Binding("Text", bindingSource1, "SubProperty"); binding.FormattingEnabled = true; binding.DataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged; binding.ControlUpdateMode = ControlUpdateMode.OnPropertyChanged; textBox.DataBindings.Add(binding); 

より詳細な例。私はそれをやってきました、そして真剣にそれは至福です。 IMOはwinformsプロジェクトを管理する唯一の方法です。 – jnm2

答えて

2

あなたは間接の層を提供するために、BindingSourceを必要としています。あなたが怒っていないBindingSource and BindingNavigator in C# 2.0

+1

ありがとう、それは動作します。デザイナを使用する代わりに実行時に作成されたBindingSourceを処分することは本当に必要ですか? – Notoriousxl

0

あなたが代わりにこのようにそれをしようとする場合があります:

Binding binding = 
    new Binding("Text", masterViewModel.SelectedDetail, "SubProperty"); 
+0

この方法では、 "SelectedDetail"プロパティが変更された場合、テキストボックスは更新されません。 – Notoriousxl

+0

@Notoriousxl:ああ、わかります。 SelectedDetailでSubPropertyChangedイベントを処理し、そこからSelectedDetailChangedを呼び出すことができます。それはうまくいくかもしれない。 –

+0

プロパティパスの利点(点線の "SelectedDetail.SubProperty"文字列)を維持しながら、より自動で汎用的なものを探していました。 (汚れて)回避策として、私はすでに、(IsNull()メソッドをDetailViewModelに追加した後で)バインディングのFormatおよびParseイベントを処理しています。コントロールがnull DetailViewModelを返した場合、それをDetailViewModel IsNull )メソッドはtrueを返します。ビューモデルSelectedDetailのIsNull()がtrueを返した場合、それをヌル値に変換します。 – Notoriousxl

関連する問題