2011-03-04 74 views
2

想象一個簡單的場景,其中包含一個包含按鈕和一些空白區域的WPF窗口。單擊該按鈕將創建一個新的自定義/用戶控件,並將其隨機放置在窗口的某個位置。MVVM和控件創建

單擊其中一個控件將從窗口中刪除它。

所以,現在我有一個ViewModel ala MVVM,它爲「創建新」按鈕公開一個ICommand,但創建新控件的代碼在哪裏存在?每個控件都可能有自己的ViewModel,它可以處理它的刪除和定位。

可以在窗口沒有代碼的情況下實現,並且ViewModel沒有真正的視圖知識嗎?

回答

1

導致控件創建的代碼住在您的「主」ViewModel中。

實際上創建控件的代碼是容器。

所以它會去是這樣的:

void AddControlCommandExecuted() { 
    var container = // resolve your DI container here 

    // Now use the container to resolve your "child" view. For example, 
    // if using UnityContainer it could go like this: 
    var view = container.Resolve<ChildView>(); 

    // Of course you can also resolve the ViewModel if your program is 
    // "ViewModel-first" instead of "View-first". 

    // Does the ChildViewModel need some properties to be set? 
    var viewModel = (ChildViewModel)view.DataContext; 
    viewModel.StringProperty = "blah"; 

    // Now get a reference to the region in your View which will host 
    // the "child" views. 
    var regionManager = container.Resolve<IRegionManager>(); 
    var region = regionManager.Regions["MyRegionName"]; 

    // Finally add the view to the region. You can do it manually, you 
    // can use the concept of "navigation" if your MVVM framework has one 
    // (I 'm using Prism, which does), etc etc. 
    region.Add(view); 
} 

更新:當寫答案,我忘了,不是所有的MVVM框架有地區如棱鏡一樣。所以請原諒上面的代碼的特殊性,因爲它並沒有真正改變任何東西。你只需要自己構建像Region抽象的東西。讓我們來看看:

class MyViewModel { 
    public event EventHandler<ChildViewModelAddedEventArgs> ChildViewModelAdded; 
} 

MyView將然後附加一個事件處理該事件,並從裏面ChildViewModelAddedEventArgs拿起ChildView實例,以便它可以被添加到ItemsControl它是沒有你的視圖模型與這樣搞亂的父細節。

當然這意味着您現在需要一些代碼隱藏功能,但除非您使用自己提供此類服務的框架,否則無法提供幫助。

+0

重新更新:這很好,我熟悉棱鏡和你的答案已經解決了我的問題:)有趣的是,我有一種類似的難題最近在採訪中給我,但我提出的方法並不適合這種情況。 – Ian 2011-03-04 20:46:57

1

這應該可以通過ItemsControl上的一些非常小心的數據綁定來實現,不知道如何實現佈局,但是您將擁有包含子視圖模型集合的父視圖模型,然後將由ItemsControl執行佈局。當父ViewModel創建子ViewModel時,它應該注入一個RelayCommand作爲lambda表達式,以從父集合中刪除並清除子ViewModel。

+0

我認爲這也是一個很好的建議。這是一個恥辱,我不能作爲答案投票。我可以給你一個投票,雖然:) – Ian 2011-03-04 20:48:18