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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18890099/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 09:40:41  来源:igfitidea点击:

Change style in ModelView (MVVM + WPF)

c#wpfxamlmvvmstyles

提问by Josep B.

I have an application developed in WPF using the MVVM pattern (MVVM Light Toolkit).

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

So far, I had no problems, until it is time to change at runtime the style associated with some of my controls, a set of MenuItems. (They can have up to three different styles).

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

If I was not working with MVVM I could solve it using the command:

如果我不使用 MVVM,我可以使用以下命令解决它:

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

But because I want do it completely in MVVM, I've done these tests to achieve that:

但是因为我想在 MVVM 中完全做到这一点,所以我已经完成了这些测试以实现这一目标:

1) Try to change the style with a binding (this has not worked):

1)尝试使用绑定更改样式(这不起作用):

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

And in the ViewModel:

在 ViewModel 中:

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

2) Change the style with DataTrigger (this has not worked too. Raises an exception (Style Trigger to Apply another Style)):

2) 使用 DataTrigger 更改样式(这也不起作用。引发异常(Style Trigger to Apply another Style)):

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


At the end, I managed to solve it, using a Combox using the following code (I only use the ComboBox to change the style of the MenuItems so it is invisible). Got the idea from (How can I change an elements style at runtime?):

最后,我设法解决了它,使用 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>

And in my ViewModel:

在我的 ViewModel 中:

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

I'd rather use a cleaner way. Any suggestions? A piece of code would be very helpful.

我宁愿使用更清洁的方式。有什么建议?一段代码会很有帮助。

回答by Omri Btian

Since you are keeping your styles in you resources, cleaner approch would be to use IMultiValueConverter's with you first approch something like this:

由于您将样式保留在您的资源中,因此更简洁的方法是使用 IMultiValueConverter 与您首先使用类似的方法:

ViewModel

视图模型

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

Xaml:

Xml:

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

In the converter find the style you want and apply it

在转换器中找到您想要的样式并应用它

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();
    }
}

Taken out from Steven Robbins's answer in this post

摘自史蒂文罗宾斯在这篇文章中的回答