2009-01-04 108 views
29

我試圖創建一個自定義控件 - 一個按鈕 - 根據數據上下文中屬性的值,它將應用多種樣式。WPF樣式的綁定

什麼我正在使用類似的東西在想:

<Button Style="{Binding Path=ButtonStyleProperty, Converter={StaticResource styleConverter}}" Text="{Binding Path=TextProp}" /> 

而在代碼...實現一個的IValueConverter這確實類似下面的代碼東西在ConvertTo方法:

switch(value as ValueEnums) 
{ 
    case ValueEnums.Enum1: 
     FindResource("Enum1ButtonStyle") as Style; 
    break; 

    ... and so on. 
} 

然而,我不完全確定如何拉出樣式對象,即使這是可能的...

我在做什麼t他的意思是時間正在處理DataContextChanged事件,然後將處理程序附加到綁定到按鈕的對象的PropertyChanged事件上,然後在那裏運行switch語句。

它不完美,但直到我可以找到更好的解決方案,它似乎是我必須使用的。

回答

35

如果要更換整個風格(而不僅僅是它的元素),那麼你就可能會將這些樣式存儲在資源中。你應該能夠沿着線做一些事情:

<Button> 
    <Button.Style> 
     <MultiBinding Converter="{StaticResource StyleConverter}"> 
      <MultiBinding.Bindings> 
       <Binding RelativeSource="{RelativeSource Self}"/> 
       <Binding Path="MyStyleString"/> 
      </MultiBinding.Bindings> 
     </MultiBinding> 
    </Button.Style> 
</Button> 

通過使用MultiBinding和使用自我作爲第一裝訂那麼我們就可以查找的資源在我們的轉換器。該轉換器需要實現IMultiValueConverter(而不是的IValueConverter),可以是這個樣子:

class StyleConverter : IMultiValueConverter 
{ 
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     FrameworkElement targetElement = values[0] as FrameworkElement; 
     string styleName = values[1] as string; 

     if (styleName == null) 
      return null; 

     Style newStyle = (Style)targetElement.TryFindResource(styleName); 

     if (newStyle == null) 
      newStyle = (Style)targetElement.TryFindResource("MyDefaultStyleName"); 

     return newStyle; 
    } 

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

這不是我經常這樣做,但應該從內存:)

+0

謝謝史蒂夫 - 這正是我想要做的:) – 2009-01-05 04:51:12

+0

不用擔心。與WPF中的所有內容一樣,可能還有另外10路,但這種方式看起來很乾淨並且「設計師友好」:) – 2009-01-05 08:34:58

14

看來你需要使用DataTrigger類。它允許你根據它的內容對你的按鈕應用不同的樣式。

例如下面的樣式將按鈕的背景屬性更改爲紅色基於數據上下文對象的屬性值

<Style x:Key="ButtonStyle" TargetType="{x:Type Button}"> 
    <Style.Triggers> 
     <DataTrigger Binding="{Binding Path="Some property"}" 
        Value="some property value"> 
      <Setter Property="Background" Value="Red"/> 
     </DataTrigger> 
    </Style.Triggers> 
</Style> 
+0

雖然你是正確的用能基礎上的數據應用樣式我更願意只是完全切換風格 - 否則它們會變得太混亂...... – 2009-01-05 04:52:09

8

工作對於我們這些誰不能使用多值轉換器(我在看你SL4和WP7 :),感謝Steven的回答,我找到了使用普通數值轉換器的方法。

唯一的假設是樣式值包含在所設置樣式的屬性中。

因此,如果您使用的是MVVM模式,則樣式值(例如TextSmall,TextMedium,TextLarge)被假定爲視圖模型的一部分,您所要做的就是傳遞定義名稱的轉換器參數的風格。

例如,假設您的視圖模型屬性:

public string ProjectNameStyle 
{ 
    get { return string.Format("ProjectNameStyle{0}", _displaySize.ToString()); } 
} 

申請方式:

<Application.Resources> 
    <Style x:Key="ProjectNameStyleSmall" TargetType="TextBlock"> 
     <Setter Property="FontSize" Value="40" /> 
    </Style> 
    <Style x:Key="ProjectNameStyleMedium" TargetType="TextBlock"> 
     <Setter Property="FontSize" Value="64" /> 
    </Style> 
    <Style x:Key="ProjectNameStyleLarge" TargetType="TextBlock"> 
     <Setter Property="FontSize" Value="90" /> 
    </Style> 

XAML視圖:

<TextBlock 
     Text="{Binding Name}" 
     Style="{Binding ., Mode=OneWay, Converter={cv:StyleConverter}, ConverterParameter=ProjectNameStyle}"> 

與您StyleConverter類實施的IValueConverter:

public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
{ 
    if (targetType != typeof(Style)) 
    { 
     throw new InvalidOperationException("The target must be a Style"); 
    } 

    var styleProperty = parameter as string; 
    if (value == null || styleProperty == null) 
    { 
     return null; 
    } 

    string styleValue = value.GetType() 
     .GetProperty(styleProperty) 
     .GetValue(value, null) 
     .ToString(); 
    if (styleValue == null) 
    { 
     return null; 
    } 

    Style newStyle = (Style)Application.Current.TryFindResource(styleValue); 
    return newStyle; 
} 

請注意,這是WPF代碼,因爲轉換器是從MarkupExtension以及IValueConverter派生而來的,但是如果您使用靜態資源並添加更多支腳作爲TryFindResource方法,它將在SL4和WP7中工作,不存在。

希望能幫助別人,再次感謝Steven!

1

視圖模型

private Style _dynamicStyle = (Style)Application.Current.FindResource("Style1"); 
     public Style DynamicStyle 
     { 
      get { return _dynamicStyle; } 
      set 
      { 
       _dynamicStyle = value; 
       OnPropertyChanged("DynamicStyle"); 
      } 

     } 

public event PropertyChangedEventHandler PropertyChanged; 

    private void OnPropertyChanged(string propertyName) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 

在你的視圖模型實現一個屬性,然後動態地更改任何你想了下方的風格。

DynamicStyle=(Style)Application.Current.FindResource("Style2");// you can place this code where the action get fired 

查看

然後設置的DataContext值,然後執行以下代碼在您看來

<Button Style="{Binding DynamicStyle,Mode=TwoWay}"/>