2013-07-01 21 views
2

我對WPF比較陌生,遇到了用戶控件的一些困難。WPF:動態更改相同類型的所有用戶控件的依賴項屬性值

請考慮以下情形: 我有一個用戶控件WPF應用程序,說

MySpecialButtonControl 

這個「按鈕」有兩儀「舊式」和「newStyle」(由枚舉「AppearanceStyle規定「),它們由一個依賴屬性具有名稱

MyLayoutProperty 

回調函數必須進行這改變了佈局的代碼控制。 下面是我想要做的: 我需要在運行時在代碼隱藏文件中立即更改此窗口中用戶控件的所有(!)實例的外觀。

綁定(例如)一個屬性到UC的各個實例像

Binding binding = new Binding("AppearanceStyle"); 
binding.Source = myOptionsClass; 
this.myButton.SetBinding(UserControls.MySpecialButtonControl.MyLayoutProperty, binding); 

工作得很好。但是,如何直接更改所有UC實例的依賴屬性,而無需遍歷UCs集合等?有沒有什麼方法可以在WPF/C#中實現這一點?

我試圖通過使用樣式來解決這個問題,但是由於它已經在使用中(並且使用這種樣式的UCs已經被繪製),所以在運行時改變由所有UCs本身共享的樣式是不可能的。

接下來,我試圖用一個動態資源在風格上是這樣的:

<uc:MySpecialButtonControl x:Key="myFakeButton" ></uc:MySpecialButtonControl > 

    <Style x:Key="myButtonStyle" TargetType="uc:MySpecialButtonControl "> 
     <Setter Property="MyLayoutProperty" Value="{DynamicResource myFakeButton}"></Setter> 
    </Style> 

這讓我在運行時更改「MyLayoutProperty」爲「myFakeButton」這是我想要的一半,但即使谷歌搜索一段時間後,我仍然無法找到一種方法將「myFakeButton」的「MyLayoutProperty」綁定到我真正需要的setter上。

任何幫助將不勝感激!

更新 我試圖執行由邁克爾提供的解決方案,但不幸的是,我得到了以下異常:

PropertyMetadata is already registered for type 'MySpecialButtonControl'. 

一些google搜索後(見MSDN)我發現OverrideMetadata通話應該放在我做的「MySpecialButtonControl」的靜態構造函數中:

static MySpecialButtonControl() 
{ 
    DefaultStyleKeyProperty.OverrideMetadata(
    typeof(MySpecialButtonControl), 
    new FrameworkPropertyMetadata(typeof(MySpecialButtonControl))); 
} 

Now ,應用程序編譯。現在它完美地工作。

+0

如果將所有控件綁定到myOptionsClass對象,並且此對象作爲單例實現(只有一個活動的類實例),則只需更改myOptionsClass的綁定屬性即可更新所有控件。如果myOptionsClass實現了INotifyPropertyChanged或者使用了依賴屬性,那麼應該將已更改的值自動複製到UC的每個實例(這就是數據綁定的全部內容) –

+0

感謝這個想法 - 它可以將UCs手動綁定到Dependency屬性,但這不是我想要的:我不想爲每個控件手動執行數據綁定。假設我在代碼的某個地方動態地創建了一個新的UC(可能是一個非常複雜的場景),並且「忘記」將它綁定到myOptionClass。 =>然後通過改變Dependcy屬性來改變它的外觀。 =>沒有一個好的代碼維護。 – user2539206

回答

1

我不完全相信我遵循,但我會嘗試一個答案。請評論這是否接近,我會編輯,直到我們到達那裏。

WPF中的所有控件都有一個屬性DefaultStyleKey。任何派生的自定義控件或用戶控件都可以使用此屬性來設置默認樣式的關鍵點。在運行時,框架將嘗試查找此密鑰的資源。通常將默認樣式鍵設置爲等於該類的運行時類型。

public MySpecialButtonControl() 
{ 
    DefaultStyleKeyProperty.OverrideMetadata(
     typeof (MySpecialButtonControl), 
     new FrameworkPropertyMetadata(typeof (MySpecialButtonControl))); 

    InitializeComponent(); 
} 

當放置在窗口控制,該框架將在現有資源尋找與由DefaultStyleKey定義的關鍵資源。資源可以在許多地方定義。谷歌「WPF資源解析」瞭解更多信息。最簡單的示例是顯示App.xaml中定義的默認樣式。

<Application.Resources> 

    <!-- the default style for MySpecialButtonControls --> 
    <Style x:Key="{x:Type uc:MySpecialButtonControl}" 
      TargetType="{x:Type uc:MySpecialButtonControl}" 
      BasedOn="{StaticResource {x:Type UserControl}}" > 
     <Setter Property="Background" Value="Blue" /> 
    </Style> 

</Application.Resources> 

現在假設您有兩種不同的樣式,您希望在運行時切換。您可以在App.xaml中定義這些樣式。

<Application.Resources> 

    <!-- the first style --> 
    <Style x:Key="Style1" 
      TargetType="{x:Type uc:MySpecialButtonControl}" 
      BasedOn="{StaticResource {x:Type UserControl}}"> 
     <Setter Property="Background" Value="Blue" /> 
    </Style> 

    <!-- the second style --> 
    <Style x:Key="Style2" 
      TargetType="{x:Type uc:MySpecialButtonControl}" 
      BasedOn="{StaticResource {x:Type UserControl}}"> 
     <Setter Property="Background" Value="Red" /> 
    </Style> 

    <!-- the default style, now based on Style1 --> 
    <Style x:Key="{x:Type uc:MySpecialButtonControl}" 
      TargetType="{x:Type uc:MySpecialButtonControl}" 
      BasedOn="{StaticResource Style1}" /> 

</Application.Resources> 

在運行時,可以這樣做來切換控件的默認樣式。

private void Button_Click(object sender, RoutedEventArgs e) 
{ 
    // get the style resources 
    var style1 = FindResource("Style1") as Style; 
    var style2 = FindResource("Style2") as Style; 
    var defaultStyle = FindResource(typeof (MySpecialButtonControl)) as Style; 
    if (style1 == null || style2 == null || defaultStyle == null) 
     return; 

    // create a new style based on the "other" style 
    var newDefaultStyle = new Style(
     typeof (MySpecialButtonControl), 
     (defaultStyle.BasedOn == style1 ? style2 : style1)); 

    // set the application-level resource to the new default style 
    Application.Current.Resources[typeof (MySpecialButtonControl)] = newDefaultStyle; 
} 

這是否更接近?

+0

謝謝你的答案邁克爾!我相信這是實現我想要的一種方式 - 我會立即明天嘗試。 – user2539206

+0

還有一個問題:如果您不能使用樣式文件,您將如何解決問題(想象一下UC佈局中的更改如此複雜且具有許多相互依賴關係,以至於無法用XAML中的簡單樣式表示,但需要用C#實現)。有沒有辦法觸發UC的所有(!)實例的依賴屬性(MyLayoutProperty)的值的變化,而無需手動將「myOptionsClass」綁定到每個UC? – user2539206

+0

我想我現在可以自己回答我的問題。 :)我可以創建兩個(或更多)不同的樣式,它們的依賴項屬性值不同。然後改變樣式將自動觸發依賴性特性回調函數,我可以在切換佈局時放置任何必須執行的代碼。 – user2539206

相關問題