简体   繁体   中英

WPF MVVM change static resource style dynamically

I am new to WPF and here is what I am trying to do. I want to change a button's style, which is a static resource, based on whether a radio button is checked on not. Below is sample code:

<RadioButton Name="rbInfoCorrect"
             GroupName="InfoQuestion"
             cal:Message.Attach="ShouldProceed">
      <RadioButton.Content>
        <TextBlock Text="Yes" Foreground="White"/>
      </RadioButton.Content>
</RadioButton>
<RadioButton Name="rbInfoNotCorrect"
             GroupName="InfoQuestion"
             cal:Message.Attach="ShouldStop">
      <RadioButton.Content>
        <TextBlock Text="No" Foreground="White"/>
      </RadioButton.Content>
</RadioButton>


<Button x:Name="btnProceed" cal:Message.Attach="Proceed">
  <Button.Style>
    <Style TargetType="Button" BasedOn="{StaticResource WhiteButton}"/>
  </Button.Style>
</Button>
<Button x:Name="btnStop" cal:Message.Attach="Stop">
  <Button.Style>
    <Style TargetType="Button" BasedOn="{StaticResource WhiteButton}"/>
  </Button.Style>
</Button>

So when 'Yes' is checked, I want to change the 'Proceed' button style to BlueButton (another static resource) and when 'No' is checked, I want to change the 'Stop' button style to BlueButton. Of course this is part of a bigger problem so I just trying to be specific with the sample example.

The part I am stuck at is how to update the StaticResource from WhiteButton to BlueButton based on the radio button checked status. Any direction would be greatly appreciated.

Thanks.

You don't need to change the whole Style to do that. You can just add a simple DataTrigger to react directly to the Checkbox.IsChecked property. It's far simpler to declare the Style s like this instead:

<Style x:Key="ProceedButtonStyle" TargetType="{x:Type Button}">
    <Setter Property="Background" Value="White" />
    <Style.Triggers>
        <DataTrigger Binding="{Binding IsChecked, ElementName=rbInfoCorrect}" 
            Value="True">
            <Setter Property="Background" Value="Blue" />
        </DataTrigger>
    </Style.Triggers>
</Style>

<Style x:Key="StopButtonStyle" TargetType="{x:Type Button}">
    <Setter Property="Background" Value="White" />
    <Style.Triggers>
        <DataTrigger Binding="{Binding IsChecked, ElementName=rbInfoNotCorrect}" 
            Value="True">
            <Setter Property="Background" Value="Blue" />
        </DataTrigger>
    </Style.Triggers>
</Style>

Even if you want more properties to change, you can just declare the default ones as plain Setter s and the ones triggered by the Checkbox.IsChecked property inside the DataTrigger . If you have lots of common properties in the two Style s, then you can still declare them all in one and base the other one on that one and just add the different DataTrigger .

We can replace the entire style using IMultiValue Converter.

For your requirement I came up with this example

public class StyleConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType,
       object parameter, CultureInfo culture)
        {
            if (values.Length < 1)
                return Binding.DoNothing;
            bool isCorrect = (bool)values[0];
            bool isNotCorrect = (bool)values[1];
            Style firstStyle = (Style)values[2];
            Style secondStyle = (Style)values[3];
            if (isCorrect)
                return firstStyle;
            if (isNotCorrect)
                return secondStyle;
            return Binding.DoNothing;

        }

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

XAML

<Window x:Class="StackWpf.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:StackWpf"
        Title="MainWindow" Name="window" Height="350" Width="525"  >
    <Window.Resources>

        <ResourceDictionary>
            <Style TargetType="Button" x:Key="WhiteStyle">
                <Setter Property="Background" Value="White"/>
            </Style>
            <Style TargetType="Button" x:Key="BlueStyle">
                <Setter Property="Background" Value="Blue"/>
            </Style>
            <local:StyleConverter x:Key="styleConverter"/>
        </ResourceDictionary>
    </Window.Resources>

    <Grid>
        <RadioButton Name="rbInfoCorrect" IsChecked="False"
             GroupName="InfoQuestion" Margin="80,19,382,257">
            <RadioButton.Content>
                <TextBlock Text="Yes" Foreground="Black"/>
            </RadioButton.Content>
        </RadioButton>
        <RadioButton Name="rbInfoNotCorrect" IsChecked="False"
             GroupName="InfoQuestion" Margin="80,38,391,257">
            <RadioButton.Content>
                <TextBlock Text="No" Foreground="Black"/>
            </RadioButton.Content>
        </RadioButton>
        <Button Content="Button" Margin="80,114,294,161">
            <Button.Style>


                        <MultiBinding Converter="{StaticResource styleConverter}">
                            <Binding ElementName="rbInfoCorrect"
                             Path="IsChecked" />
                            <Binding ElementName="rbInfoNotCorrect"
                             Path="IsChecked" />
                            <Binding Source="{StaticResource WhiteStyle}" />
                            <Binding Source="{StaticResource BlueStyle}" />
                        </MultiBinding>


            </Button.Style>
        </Button>

    </Grid>
</Window>

I have used this good article http://social.msdn.microsoft.com/Forums/vstudio/en-US/b25973bb-9e9c-4a99-8234-39a042e0a478/apply-styles-dynamically-to-buttons-in-xaml?forum=wpf earlier to tackle my issue.

I'm not sure if you can replace the complete Style but you can user a DataTrigger to change some properties of the button:

    <Button.Style>
      <Style TargetType="Button" BasedOn="{StaticResource WhiteButton}">
        <Style.Triggers>
          <DataTrigger Binding="{Binding ElementName=rbInfoCorrect, Path=IsChecked}" Value="True">
            <Setter Property="Background" Value="White" />
          </DataTrigger>
          <DataTrigger Binding="{Binding ElementName=rbInfoCorrect, Path=IsChecked}" Value="False">
            <Setter Property="Background" Value="Blue" />
          </DataTrigger>
        </Style.Triggers>
      </Style>
    </Button.Style>

Check out http://Globalizer.codeplex.com .

It switches out the entire style when it switches a language.

You basically look up the style in the resource dictionary, kill it and load a new one.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM