2009-06-08 93 views
4

我MainView.xaml包含我的智能表查看:如何在我的ViewModel層次結構中冒出更改?

<Grid Margin="10"> 
    <views:SmartForm/> 
</Grid> 

的智能表視圖加載一個ItemsControl

<Grid Margin="10"> 
    <ItemsControl 
     ItemsSource="{Binding DataTypeViews}"/> 
</Grid> 

這是DataTypeViews的一個ObservableCollection:

List<FormField> formFields = new List<FormField>(); 
formFields.Add(new FormField { IdCode = "firstName", Label = "First Name", Value = "Jim" }); 
formFields.Add(new FormField { IdCode = "lastName", Label = "Last Name", Value = "Smith" }); 
formFields.Add(new FormField { IdCode = "address1", Label = "Address 1", Value = "123 North Ashton Rd." }); 
formFields.Add(new FormField { IdCode = "address2", Label = "Address 2", Value = "Box 23434" }); 
formFields.Add(new FormField { IdCode = "city", Label = "City", Value = "New Haven" }); 
formFields.Add(new FormField { IdCode = "state", Label = "State", Value = "NM" }); 
formFields.Add(new FormField { IdCode = "zip", Label = "Zip Code", Value = "34234" }); 

foreach (FormField formField in formFields) 
{ 
    DataTypeView dtv = new DataTypeView(); 
    DataTypeViewModel dtvm = new DataTypeViewModel(formField); 
    dtv.DataContext = dtvm; 
    DataTypeViews.Add(dtv); 
} 

每個視圖顯示了建立表單的標籤和文本框:

<Grid> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="90"/> 
     <ColumnDefinition Width="400"/> 
    </Grid.ColumnDefinitions> 
    <StackPanel Orientation="Horizontal" Grid.Column="0"> 
     <TextBlock Text="{Binding Label}" FontSize="14"/> 
     <TextBlock Text=": " FontSize="14"/> 
    </StackPanel> 
    <TextBox Grid.Column="1" Text="{Binding Value}" FontSize="12"/> 
</Grid> 

如何將DataTypeViewModel中發生的文本框更改冒泡到SmartFormViewModel中?

或換句話說:如果ViewModel A包含ViewModel B的集合,並且在ViewModel B中發生更改,那麼如何將該更改提交給ViewModel A?

回答

5

您可以讓父虛擬機連接到子虛擬機上的PropertyChanged事件。這是怎樣的一個PITA的跟蹤已加入誰的孩子/刪除諸如此類,所以你可能會改爲考慮將你的孩子的VM在我ItemObservableCollection

public sealed class ItemObservableCollection<T> : ObservableCollection<T> 
    where T : INotifyPropertyChanged 
{ 
    public event EventHandler<ItemPropertyChangedEventArgs<T>> ItemPropertyChanged; 

    protected override void InsertItem(int index, T item) 
    { 
     base.InsertItem(index, item); 
     item.PropertyChanged += item_PropertyChanged; 
    } 

    protected override void RemoveItem(int index) 
    { 
     var item= this[index]; 
     base.RemoveItem(index); 
     item.PropertyChanged -= item_PropertyChanged; 
    } 

    protected override void ClearItems() 
    { 
     foreach (var item in this) 
     { 
      item.PropertyChanged -= item_PropertyChanged; 
     } 

     base.ClearItems(); 
    } 

    protected override void SetItem(int index, T item) 
    { 
     var oldItem = this[index]; 
     oldItem.PropertyChanged -= item_PropertyChanged; 
     base.SetItem(index, item); 
     item.PropertyChanged -= item_PropertyChanged; 
    } 

    private void item_PropertyChanged(object sender, PropertyChangedEventArgs e) 
    { 
     OnItemPropertyChanged((T)sender, e.PropertyName); 
    } 

    private void OnItemPropertyChanged(T item, string propertyName) 
    { 
     ItemPropertyChanged.Raise(this, new ItemPropertyChangedEventArgs<T>(item, propertyName)); 
    } 
} 

那麼你的母VM可以只聽任何改變都需要孩子項目與:

_formFields.ItemPropertyChanged += (s, e) => Foo(); 
0

非WPF的方式是在DataTypeViewModel上創建一個靜態事件。這允許您在適當時(在屬性設置器或屬性更改處理程序中)從DataTypeViewModel中觸發事件。當然,你還必須在SmartForm中註冊一個偵聽器給事件(要求SmartForm知道DataTypeViewModel類型)。

或者我認爲你可以創建自己的自定義路由事件。

0

雖然肯特是正確的,但並非兒童視圖模型中的所有變化都與屬性有關,有些可能會比語義更有語義。在這種情況下,實施Chain of Responsibility pattern的變體可能會非常合適。

總之

  • 使所有子視圖模型知道「主處理器對象」擁有處理各種改變事件的方法。與該對象的通信可以通過事件或消息進行,具體取決於更改的複雜性。
  • 這個主處理程序對象註冊一個處理對象的集合,它將處理更改事件,每個對象一個。它們可以按照原始模式鏈接起來,或者可以在快速收集(例如字典)中註冊以獲得性能。
  • 使此處理程序對象向適當的註冊處理程序發送相應的更改。

「主」處理程序不一定是單身人士,它的註冊表可以依賴於父視圖模型本身。

希望這是足夠清晰的(對不起,沒有把代碼)

8

我認爲你應該使用介體模式which you can read about here

基本上它是一個靜態類,允許ViewModel(或任何類的事情)相互溝通並來回傳遞參數。

基本上ViewModel A開始監聽特定的消息類型(例如ViewModelBChanged),並且每當發生該事件時ViewModelB只是通知正在偵聽此消息類型的任何人,它也可以傳遞它想要的任何信息。

這裏是介體的骨架。

public static class MyMediator 
{ 
    public static void Register(Action<object> callback, string message); 

    public static void NotifyColleagues(string message, object args); 
} 

視圖模型A將做到這一點(可能是在構造函數):

MyMediator.Register(ProcessMessage,"ViewModelBChanged") 

,然後將不得不宣佈這樣的功能:

void ProcessMessage(object args) 
{ 
    //Do some important stuff here 
} 

和視圖模型B將調用此只要它想告訴ViewModel A

MyMediator.NotifyColleagues("ViewModelBChanged",this); 

調解器類將負責調用viewModel的回調函數。然後大家都很開心。

個人而言,我喜歡在一個靜態類將這些字符串消息值這樣

static class MediatorMessages 
{ 
    public static string ViewModelBChanged= "ViewModelBChanged"; 
} 

所以,你可以做以下的(而不是上面):

MyMediator.Register(ProcessMessage,MediatorMessages.ViewModelBChanged) 
MyMediator.NotifyColleagues(MediatorMessages.ViewModelBChanged,this); 

如果這還不清楚只是谷歌MVVM調解員,並點擊你的心內容:)

相關問題