2009-01-04 69 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}"/>