2011-04-19 19 views
2

這裏所說的特定功能是我的「問題」,我想解決:MVVM +觀的貫徹落實該視圖模型

我有許多「僅查看」特定功能,例如:

  • 更改在運行時查看的ResourcesDictionary(從黑皮膚變藍或其他)
  • 保存和恢復視圖的觀點一樣,大小特定的設置,或者由用戶
  • ...
  • 設置網格屬性

所有這些功能都與ViewModel無關,因爲它們確實是特定的視圖,並且可能只適合ViewModel的一個客戶端(視圖)(在ViewModel擁有多個客戶端的情況下)。上面的例子只是我想實現的大量功能中的兩個,所以我需要一個更通用的解決方案,而不是僅適用於這兩個示例的解決方案。

當一個解決方案的思維我來到下列兩種方法

  • 創建從DependancyObject繼承ViewBase。我不喜歡這個解決方案,因爲它在某種程度上打破了View沒有代碼的MVVM模式的想法。爲了調用這些方法,我需要引用ViewModel中的視圖,這也否定了分離關注的想法。
  • 創建一個IView界面。像第一種方法一樣髒。每個視圖都需要實現IView,而且它有代碼。此外,ViewModel需要「以某種方式」知道IView實現以調用其方法
  • 將ViewModel的屬性綁定到View的觸發器,行爲,命令。這種方法似乎是最好的,但我認爲我會以非常快的速度運行,因爲某些功能可能不適用於這種方法。例如,僅僅將resourceDictionary綁定到View可能不起作用,因爲需要合併才能正確顯示新資源。然後再次...我只查看ViewModel中的特定功能/信息(如resourcesdictionary),但只有ViewModel的特定客戶端使用此屬性。

如果你們中的任何人已經有同樣的問題,並且對我的問題有一個智能/平滑(並且大多數是通用的)解決方案,這將會很棒。

謝謝

回答

0

當你說

我有許多「僅查看」具體例如功能:

這讓我覺得,你是混合「是什麼」和「如何」。我會解釋我的意思。

的什麼是您的應用程序要求:應用程序的

  • 改變膚色
  • 保存&恢復
    • 尺寸
    • 網格屬性

我認爲上述內容與你的ViewModel有關,你的虛擬機應該包含簡單或複雜的屬性,可以告訴你的View它想做什麼,例如,

public class SettingsViewModel 
{ 
    public Color Skin { get;set;} 
    public Size ViewSize {get;set;} 
    public GridProperties GridProperties {get;set;} 

    public void Save() {//TODO:Add code} 
    public void Restore() {//TODO:Add code} 
} 

您的視圖將綁定到該ViewModel並實現「如何」。

如果你正在創建一個web應用程序,那麼將如何使用ViewModel並創建html。如果你正在使用WPF,你將綁定到XAML中的這些屬性並創建你的UI(這可能會導致你切換出ResourceDictionaries等)

幫助我的另一件事是實現視圖和視圖之間的非對稱關係視圖模型。在最純粹的形式下,ViewModel應該對View沒有任何的瞭解,但View應該知道它需要了解的ViewModel的一切。

這就是問題分離背後的關鍵。

迴應你的「解決方案」:

  • 你的第一選擇違反MVVM原則,你讀過this article?
  • 我相信this article會幫助你來基於視圖模型與視圖選擇條款。
  • 我不知道你會遇到什麼樣的「限制」,但是WPF非常強大,並且會有可用的解決方案。
0

我同意查看特定功能應該保留在視圖(保存並恢復窗口大小,將焦點設置爲特定控件等)。

但我不同意介紹一個IView接口是'髒'的。這是一種常見的設計模式,稱爲Separated Interface,在Martin Fowler的「企業應用程序體系結構模式」一書中有介紹。此外,只要代碼涉及查看特定功能,代碼隱藏就不是「邪惡」的。不幸的是,這是MVVM社區中常見的誤解。

如果您介紹一種IView界面方法,那麼您可能會發現有趣的改變。它通過這個界面解決了我們的問題。您將在示例應用程序中看到這一點。

1

在View和ViewModel之間沒有引入耦合的情況下,最簡單的方法是使用Messenger(在某些框架中也稱爲Mediator)。 ViewModel只是廣播一個「更改主題」消息,而View則訂閱該消息。使用從MVVM點燃Messenger類,你可以做類似的規定:

消息定義

public class ThemeChangeMessage 
{ 
    private readonly string _themeName; 
    public ThemeChangeMessage(string themeName) 
    { 
     _themeName = themeName; 
    } 

    public string ThemeName { get { return _themeName; } } 
} 

視圖模型

Messenger.Default.Send(new ThemeChangeMessage("TheNewTheme"); 

查看代碼隱藏

public MyView() 
{ 
    InitializeComponent(); 
    Messenger.Defaut.Register<ThemeChangeMessage>(ChangeTheme); 
} 

private void ChangeTheme(ThemeChangeMessage msg) 
{ 
    ApplyNewTheme(msg.ThemeName); 
} 
1

我很久以前就採用了模式是爲人而不是人爲模式的思維方式。通常情況下,您會看到MVVM不適合並解決它的情況,非常聰明的人想出瞭解決方法,同時保持純粹的MVVM外觀。但是,如果您訂閱了我的思想派系,或者如果您只是想保持簡單,另一種方法是允許ViewModel引用視圖;通過一個界面當然,或者那隻會是可怕的編程練習。現在的問題是,如何將視圖引入視圖模型?

最簡單的方法是在視圖的dataContextChanged事件中執行此操作。但是,如果你想嘗試一些不同的東西,那麼使用附加屬性或依賴項屬性將視圖注入視圖模型怎麼樣?

我已經在一些WPF項目上成功地使用了這種技術,並且不覺得髒或以某種方式被破壞。我稱之爲MiVVM or Model Interface-to-View ViewModel

該模式很簡單。你的用戶控件應該有一個接口,稱之爲IMyView。然後在視圖模型,你有型IMyView的二傳手屬性,說

然後在視圖中創建一個名爲依賴屬性這

public MyUserControl : IMyView 
{ 
    public static readonly DependencyProperty ThisProperty = 
     DependencyProperty.Register("This", typeof(IMyView), typeof(MyUserControl)); 

    public MyUserControl() 
    { 
     SetValue(ThisProperty, this); 
    } 
    public IMyView This { get { return GetValue(ThisProperty); } set { /* do nothing */ } } 
} 

終於在XAML中,你可以注入使用綁定直接查看ViewModel

<MyUserControl This="{Binding InjectedView, Mode=OneWayToSource}"/> 

試一試!我已經多次使用這個模式,並且在啓動時獲得了一次注入視圖的接口。這意味着你保持分離(可以測試Viewmodel,因爲IView可以被嘲笑),但是你可以避免許多第三方控件缺乏綁定支持。另外,它的速度很快。你知道綁定使用反射嗎?

有一個演示項目在this blog link上展示此模式。如果您使用的是無法修改的第三方控件,我會主張嘗試MiVVM的附加屬性實現。

最後,我建議找到最適合工作的工具幾乎總是最好的編程方法。如果你設定了正確的「清潔」或「正確」的代碼,你通常會打到一堵牆,你需要改變你的方法。