Search code examples
c#wpfmvvmstylesmahapps.metro

Change style of a button at runtime in wpf with multibinding


I am trying to change the style of a button at runtime depending on a bool property. In addition to that, I am using the mahapps.metro framework.

My Code:

The view:

 <UserControl.Resources>
    <Style TargetType="{x:Type Button}" x:Key="firstStyle">
        <Setter Property= "Style" Value="{StaticResource SquareButtonStyle}"/>
    </Style>
    <Style TargetType="{x:Type Button}" x:Key="secondStyle">
        <Setter Property="Style" Value="{StaticResource AccentedSquareButtonStyle}"/>
    </Style>
    <conv:ButtonMultiConverter x:Key="styleConvert"/>
</UserControl.Resources>

The button:

<Button>
    <Button.Style>
        <MultiBinding Converter="{StaticResource styleConvert}">
            <Binding  Path="ValueFilter" />
            <Binding Source="{StaticResource firstStyle}" />
            <Binding Source="{StaticResource secondStyle}" />
        </MultiBinding>
    </Button.Style>

    <iconPacks:PackIconModern  Width="30" Height="15" Kind="edit"/>
</Button>

The converter:

public class ButtonMultiConverter:  IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        var firstStyle = values[1] as Style;
        var secondStyle = values[2] as Style;

        if (values[0] is bool)
            return (bool)values[0] ? secondStyle : firstStyle;

        return firstStyle;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}

With this code I get always the following exception: "style object is not allowed to affect the style property of the object to which it applies"

What should I change on the xaml code to prevent this exception.


Solution

  • The firstStyle and secondStyle resources are invalid. As the error message says, a Style applied to an element can not have a Setter that sets the Style property of that element.

    They are however also redundant. Use SquareButtonStyle and AccentedSquareButtonStyle directly:

    <Button.Style>
        <MultiBinding Converter="{StaticResource styleConvert}">
            <Binding Path="ValueFilter"/>
            <Binding Source="{StaticResource SquareButtonStyle}"/>
            <Binding Source="{StaticResource AccentedSquareButtonStyle}"/>
        </MultiBinding>
    </Button.Style>
    

    If for any reason you really need firstStyle and secondStyle, declare them like this:

    <Style x:Key="firstStyle" TargetType="Button"
           BasedOn="{StaticResource SquareButtonStyle}"/>
    <Style x:Key="secondStyle" TargetType="Button"
           BasedOn="{StaticResource AccentedSquareButtonStyle}"/>