2011-07-07 67 views
3

我試圖在Windows窗體項目中使用MVVM模式實現master/detail場景(我瘋了,我知道)。請看下面的視圖模型:Windows窗體數據綁定和屬性路徑:如何處理可空性?

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)。

有沒有辦法處理「父」屬性(在導航路徑內)的可空性?

這裏是異常堆棧跟蹤:

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

你是不是瘋了。我一直在這樣做,而且非常認真,這是幸福的。 IMO是管理winforms項目的唯一方法。 – jnm2

回答

2

您需要BindingSource提供一個間接層。

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); 

更詳細的例子: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」字符串)。作爲一個(髒)解決方法,我已經處理綁定的Format和Parse事件(在向DetailViewModel添加IsNull()方法之後):如果控件返回空DetailViewModel,我將它轉換爲DetailViewModel,該IsView爲)方法返回true;如果視圖模型SelectedDetail的IsNull()返回true,我將它轉換爲空值。 – Notoriousxl

相關問題