2009-10-05 28 views
3

我有一些全局設置應該來自ViewModel,並且應該可用於所有UserControls中的所有DataTemplates。它包括諸如GlobalButtonMargin,GlobalStrokeWidth或GlobalWorkspaceBackgroundColor之類的東西。這些東西在視圖模型中,因爲用戶可以在運行時編輯這些設置。GlobalSettings ViewModel

你會如何以一種好的MVVM方式來實現這一點?

我想過擁有一個Singleton GlobalSettingsViewModel。這是首選方法嗎?如果是這樣,我怎樣才能從XAML獲取單例實例?

另一種方法是將GlobalSettings傳遞給我的應用程序中存在的所有ViewModel實例,以便我可以從創建DataTemplates的視圖模型中訪問。但那感覺不乾淨。

第三種方法是將ViewModel方法全部定義爲XAML資源並使用FindResource在運行時動態設置資源。

您能否勾畫出您將如何設計應用程序以支持此場景?

回答

3

我將創建該類型來將您的ViewModel表示爲一個類然後將其實例定義爲ApplicationLevel上的資源。爲整個應用程序保留單個實例,您現在可以使用StaticResource引用這些設置。例如:

<Application xmlns:myNS="clr-namespace:MyNamespace;assembly=MyAssembly" ...> 
    <Application.Resources> 
     <myNS:MySettings x:Key="Settings" /> 
    </Application.Resources> 
</Application> 

然後在windows/controls/templates/etc中。您可以使用以下訪問MySettings實例:

{Binding Source={StaticResource Settings}, Path=MyProperty} 
+0

數據類型是否可以從Settings ViewModel的INotifyPropertyChanged可靠地獲取runtimne上的更改?我一直認爲StaticRessource只會被評估一次? – bitbonk 2009-10-12 07:14:31

+0

是的,絕對。你是對的,StaticResource被評估一次,但這是分配給綁定。然而,從這一點開始,綁定就是「活着的」,所以只要你發射屬性更改通知,任何綁定的綁定都會保持最新狀態。 – 2009-10-12 13:09:24

+0

我如何從其他ViewModel對象訪問此MySettings實例? – bitbonk 2010-03-11 09:26:25

4

您可以使用靜態,您可以讀取和綁定到,使用XAML中的x:Static。我不喜歡做靜態全局設置,因爲它更像是一種反模式。

我認爲你應該考慮控制/依賴注入的反轉。這裏有很多IoC容器,但我通常使用Unity來進行依賴注入。它可在http://prism.codeplex.com

使用IoC,您可以註冊您的設置類,並在您的VM需要的數據,他們可以輕鬆地拉出你想要的設置。你的代碼看起來與此類似(如果使用unity)。

var vm = container.Resolve<SomeViewModel>(); 

public class SomeViewModel 
{ 
    public SomeViewModel(IUnityContainer container) 
    { 
     ISomeSettings settings = container.Resolve<ISomeSettings>();  
    } 
} 

編輯:或者,這裏是你可能會尋找另一種解決方案:

創建單:

class GlobalSettings : ViewModel 
{ 
    private Thickness m_globalGirth; 

    private static GlobalSettings m_instance = new GlobalSettings(); 

    public GlobalSettings() 
    { 
     GlobalGirth = new Thickness(2, 2, 2, 2); 
    } 
    public Thickness GlobalGirth 
    { 
     get { return m_globalGirth; } 
     set 
     { 
      m_globalGirth = value; 
      InvokePropertyChanged("GlobalGirth"); 
     } 
    } 

    public static GlobalSettings Instance 
    { 
     get { return m_instance; } 
     set { m_instance = value; } 
    } 
} 

然後設置您的綁定:

<Window x:Class="WpfApplication3.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:WpfApplication3="clr-namespace:WpfApplication3" 
    Title="Window1" Height="300" Width="300" MouseDoubleClick="Window_MouseDoubleClick"> 
    <Window.Resources> 
     <WpfApplication3:GlobalSettings x:Key="settings" /> 
    </Window.Resources> 
    <Grid> 
     <Border BorderThickness="{Binding Source={StaticResource settings}, Path=Instance.GlobalGirth}" 
       BorderBrush="Black" 
       Width="100" 
       Height="100" /> 
    </Grid> 
</Window> 
+0

這裏存在的問題在於其他地方。我上面提到的那些設置是全局設置,我需要爲所有我爲大量不同視圖模型編寫的數據模板進行排版。這些數據不是特定於這些視圖模型的。他們是全球性的設置。從WPF的角度來看,它們更像是資源。只有他們可以在運行時更改。例如,無論何時在任何我的數據模板中繪製線條和邊框,其厚度必須是GlobalStrokeWidth。我怎樣才能使這對所有數據模板都可用。不管這個數據模板用於什麼模式。 – bitbonk 2009-10-10 06:42:54

+0

對我原來的答案增加了另一個解決方案。 – 2009-10-10 23:34:20

+0

邊界是否會從GlobalSettings的INotifyPropertyChanged中的runtimne中更改? – bitbonk 2009-10-11 08:37:39