在ModelView中改变样式(MVVM + WPF)

6

我有一个使用MVVM模式(MVVM Light Toolkit)开发的WPF应用程序。

到目前为止,我没有遇到任何问题,直到运行时需要更改与一些控件相关联的样式,一组菜单项。(它们最多可以有三种不同的样式)。

如果我不是在使用MVVM,我可以使用命令来解决:

MenuElement_Left4.Style = (Style)FindResource("MenuButtonTabsLeft");

但是因为我想完全使用MVVM模式,所以我进行了以下测试:

1)尝试使用绑定来更改样式(但这没有成功):

<MenuItem x:Name="MenuElement_Left4" Header="Test" Style="{Binding SelectedStyle}">

在ViewModel中:
public string SelectedStyle
    {
       get { return this.selectedStyle; }
       set { this.selectedStyle = value; 
             RaisePropertyChanged("SelectedStyle");
           }
    }
    private string selectedStyle;

2) 使用DataTrigger更改样式(这也没有起作用。引发异常(使用样式触发器应用另一个样式)):

<MenuItem.Style>
    <Style TargetType="{x:Type MenuItem}">
        <Style.Triggers>
            <DataTrigger Binding="{Binding Path=TestStyle}" Value="True">
                <Setter Property="Style" Value="{StaticResource  MenuButtonTabsLeftArrow}"/>
            </DataTrigger>
            <DataTrigger Binding="{Binding Path=TestStyle}" Value="False">
                <Setter Property="Style" Value="{StaticResource  MenuButtonTabsLeft}"/>
            </DataTrigger>
        </Style.Triggers>
    </Style>
</MenuItem.Style>

最终,我使用以下代码解决了它,使用Combox(下拉框)(我只使用ComboBox更改MenuItems的样式,使其不可见)。从以下链接中获取了灵感:如何在运行时更改元素的样式?

<MenuItem x:Name="MenuElement_Left4" Header="Test" Style="{Binding ElementName=AvailableStyles, Path=SelectedItem.Tag}">
<ComboBox Name="AvailableStyles" SelectedIndex="{Binding AvailableStylesIndex}" Visibility="Collapsed">
    <ComboBoxItem Tag="{x:Null}">None</ComboBoxItem>
    <ComboBoxItem Tag="{StaticResource MenuButtonTabsLeftArrow}">MenuButtonTabsLeftArrow</ComboBoxItem>
    <ComboBoxItem Tag="{StaticResource MenuButtonTabsLeft}">MenuButtonTabsLeft</ComboBoxItem>
</ComboBox>

在我的ViewModel中:

public int AvailableStylesIndex
{
    get { return this.availableStylesIndex; }
    set
    {
        this.availableStylesIndex = value;
        RaisePropertyChanged("AvailableStylesIndex");
    }
}

我更倾向于使用更简洁的方法。有什么建议吗?提供一段代码会非常有帮助。
1个回答

10
由于您将样式保存在资源中,更清晰的方法是使用IMultiValueConverter与您的第一种方法类似这样:
ViewModel
public string SelectedStyle
{
   get { return this.selectedStyle; }
   set { this.selectedStyle = value; 
         RaisePropertyChanged("SelectedStyle");
       }
}
private string selectedStyle;

Xaml:

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

在转换器中找到你想要的样式并应用它。
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();
    }
}

这篇帖子中摘录自Steven Robbins的回答。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接