WPF在运行时更改按钮样式

时间:2018-10-15 10:21:27

标签: wpf mahapps.metro

我试图在运行时使用拨动开关打开或关闭样式。 我已经将样式添加到资源字典中,但是我不确定如何制作一些C#代码来加载或卸载资源。我所有的按钮都使用“ PassiveGlowButton”的动态资源,当我使用拨动开关时,我希望它删除“ PassiveGlowButton”,因此使用“ GlowButton”样式

“ GlowButton”后面的代码这是我想在拨动开关打开时应用的代码。在App.Xaml中的Application.resources,resourceDictionary中:

            <ResourceDictionary>
                <Style x:Key="GlowButton"  TargetType="{x:Type Button}"
                       BasedOn="{StaticResource AccentedSquareButtonStyle}">
                    <Setter Property="BorderThickness" Value="0" />
                    <Setter Property="Effect">
                        <Setter.Value>
                            <DropShadowEffect  ShadowDepth="5" Color="WhiteSmoke" BlurRadius="18"/>
                        </Setter.Value>
                    </Setter>
                    <Style.Triggers>
                        <EventTrigger RoutedEvent="Button.Loaded">
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation 
                                 Storyboard.TargetProperty="Effect.ShadowDepth"
                                 From="3.0" To="0.0" Duration="0:0:1" 
                                 AutoReverse="True" RepeatBehavior="Forever"/>
                                </Storyboard>
                            </BeginStoryboard>
                        </EventTrigger>
                        <!-- Mouse over glow -->
                        <Trigger Property="IsMouseOver" Value="True">
                            <Trigger.EnterActions>
                                <BeginStoryboard>
                                    <Storyboard>
                                        <DoubleAnimation 
                                 Storyboard.TargetProperty="Effect.BlurRadius"
                                 From="45.0" To="17.0" Duration="0:0:1" 
                                 AutoReverse="True" RepeatBehavior="Forever"/>
                                    </Storyboard>
                                </BeginStoryboard>
                            </Trigger.EnterActions>
                            <Trigger.ExitActions>
                                <BeginStoryboard>
                                    <Storyboard>
                                        <DoubleAnimation 
                                 Storyboard.TargetProperty="Effect.BlurRadius"
                                 From="15.0" To="15.0" Duration="0:0:1" 
                                 AutoReverse="True" RepeatBehavior="Forever"/>
                                    </Storyboard>
                                </BeginStoryboard>
                            </Trigger.ExitActions>
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </ResourceDictionary>
  

更新   我已经能够使用按钮设置样式,但它仅适用于名为Testbttn的按钮。有没有一种方法可以更改它以应用于Button.Style?如果我使用此方法,由于某种原因它也会失去按钮的故事板

        Style style = this.FindResource("PassiveGlowButton") as Style;
        TestBttn.Style = style;
  

更新2:解决方案是创建3种样式,一种是从加载中使用的按钮,然后是2种,一种是空白按钮,另一种是我想要的样式。   我已经附上了我在样式之间进行交换的代码。

private void ButtonStyle_Checked(object sender, RoutedEventArgs e)
    {
        Application.Current.Resources["PassiveGlowButton"] = Application.Current.Resources["PassiveGlowButtonOn"];
    }


    private void ButtonStyle_UnChecked(object sender, RoutedEventArgs e)
    {
        Application.Current.Resources["PassiveGlowButton"] = Application.Current.Resources["PassiveGlowButtonOff"];
    }

1 个答案:

答案 0 :(得分:1)

有几种方法可以做到这一点。

您要询问的内容最好重新设计为使用VisualStateManager

另一个选择是将样式重新设计为StyleViewModel。 (我建议使用一个枚举并键入样式,以便VM可以独立于样式本身使用/引用)。如果正确执行此操作,则可以更改样式类型,样式绑定将更新。

最后,您可以使用DynamicResource作为样式,并在其他位置创建默认样式资源。样式用作资源时,可以在单独的字典中使用相同的键。名称重叠,因此最后一个(或最接近层次结构中请求它的控件)将成为要使用的名称。您可以重新排列样式顺序或添加/删除样式,但是控件将在下一次加载之前更新。

每个实现都有些棘手,尽管我喜欢VisualStateManager,但我本人还是绑定修订(选项2)的粉丝。两者之间有区别。所以我不想让您感到困惑或引起争论。我只是在说明选项。

如果您确实喜欢走固定路线的样式,这是一个简单的示例,它将解决您的IMO问题。

示例:

样式

<Application x:Class="Question_Answer_WPF_App.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <Style x:Key="StyleA"
               TargetType="Button">
            <Setter Property="Background"
                    Value="Green" />
            <Setter Property="Height"
                    Value="40" />
            <Setter Property="Margin"
                    Value="4" />
        </Style>

        <Style x:Key="StyleB"
               TargetType="Button">
            <Setter Property="Background"
                    Value="Blue" />
            <Setter Property="Height"
                    Value="30" />
        </Style>
    </Application.Resources>
</Application>

枚举

namespace Question_Answer_WPF_App.ViewModels
{
    public enum Styles
    {
        StyleA,
        StyleB
    }
}

ViewModel

using System.Windows.Input;

namespace Question_Answer_WPF_App.ViewModels
{
    public class StylesViewModel : NotifyModel
    {
        private Styles selectedStyle;

        public StylesViewModel()
        {
            SelectStyleCommand = new RelayCommand(SelectStyle);
        }

        public Styles SelectedStyle
        {
            get { return selectedStyle; }
            set
            {
                selectedStyle = value;
                Notify();
            }
        }

        public ICommand SelectStyleCommand { get; }

        private void SelectStyle(object obj)
        {
            if (obj is Styles style) SelectedStyle = style;
        }
    }
}

转换器

using Question_Answer_WPF_App.ViewModels;
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;

namespace Question_Answer_WPF_App.Views
{
    public class StyleTypeConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var result = Application.Current.Resources["StyleA"];
            if (value is Styles style)
            {
                switch (style)
                {
                    case Styles.StyleB:
                        result = Application.Current.Resources["StyleB"];
                        break;
                    case Styles.StyleA:
                    default:
                        result = Application.Current.Resources["StyleA"];
                        break;
                }
            }
            return result;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            => DependencyProperty.UnsetValue;
    }
}

查看

<UserControl x:Class="Question_Answer_WPF_App.Views.StylesTestView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:ViewModels="clr-namespace:Question_Answer_WPF_App.ViewModels"
             xmlns:local="clr-namespace:Question_Answer_WPF_App.Views">

    <UserControl.Resources>
        <ViewModels:StylesViewModel x:Key="StylesViewModel" />
        <local:StyleTypeConverter x:Key="StyleTypeConverter" />
    </UserControl.Resources>

    <StackPanel>
        <Button Style="{Binding SelectedStyle, Source={StaticResource StylesViewModel}, Converter={StaticResource StyleTypeConverter}}"
                Command="{Binding SelectStyleCommand, Source={StaticResource StylesViewModel}}"
                CommandParameter="{x:Static ViewModels:Styles.StyleA}"
                Content="Select Style A" />
        <Button Style="{Binding SelectedStyle, Source={StaticResource StylesViewModel}, Converter={StaticResource StyleTypeConverter}}"
                Command="{Binding SelectStyleCommand, Source={StaticResource StylesViewModel}}"
                CommandParameter="{x:Static ViewModels:Styles.StyleB}"
                Content="Select Style B" />
    </StackPanel>
</UserControl>

结果

enter image description here enter image description here