绑定WPF样式

时间:2009-01-04 06:47:54

标签: wpf data-binding styles

我正在尝试创建一个自定义控件 - 一个按钮 - 根据数据上下文中属性的值,它将应用多种样式。

我在想的是使用类似的东西:

<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.
} 

然而,我不完全确定如何拉出样式对象,即使这是可能的......

我正在做的同时是处理DataContextChanged事件,然后将处理程序附加到绑定到按钮的对象的PropertyChanged事件 - 然后在那里运行switch语句。

它不是很完美,但在我找到更好的解决方案之前,我似乎必须使用它。

4 个答案:

答案 0 :(得分:37)

如果你想要替换整个样式(而不仅仅是它的元素),那么你可能会将这些样式存储在资源中。你应该能够做一些事情:

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

通过使用MultiBinding并使用Self作为第一个绑定,我们可以在转换器中查找资源。转换器需要实现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();
    }
}

这不是我经常做的事情,但这应该从记忆中起作用:)

答案 1 :(得分:15)

您似乎需要使用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>

答案 2 :(得分: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派生的,但如果你使用静态资源并且添加更多的腿部工作,它将在SL4和WP7中工作,因为TryFindResource方法没有#39存在。

希望能有所帮助,并再次感谢史蒂文!

答案 3 :(得分: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));
        }
    }

在ViewModel中实现一个属性,然后在下面的任何地方动态更改样式。

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

查看

然后设置 DataContext 值,然后在视图中实现以下代码

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