WPF 在运行时更改按钮样式
WPF Change button style at runtime
我正在尝试使用切换开关在运行时打开或关闭样式。
我已将样式添加到资源字典中,但我不确定如何编写一些 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>
Update
I have been able to set the style using a button but it will only apply to a button called Testbttn. Is there a way to change it to apply to Button.Style? If i use this method it also looses the storyboard of the button for some reason
Style style = this.FindResource("PassiveGlowButton") as Style;
TestBttn.Style = style;
Update 2: The solution was to create 3 styles, one the button uses from load and then 2 others, one with a blank button and one with the style i wanted.
I have attached the code i used to swap between the styles.
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"];
}
有几种方法可以做到这一点。
您的问题最好重新设计以使用 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>
结果
我正在尝试使用切换开关在运行时打开或关闭样式。 我已将样式添加到资源字典中,但我不确定如何编写一些 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>
Update I have been able to set the style using a button but it will only apply to a button called Testbttn. Is there a way to change it to apply to Button.Style? If i use this method it also looses the storyboard of the button for some reason
Style style = this.FindResource("PassiveGlowButton") as Style;
TestBttn.Style = style;
Update 2: The solution was to create 3 styles, one the button uses from load and then 2 others, one with a blank button and one with the style i wanted. I have attached the code i used to swap between the styles.
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"];
}
有几种方法可以做到这一点。
您的问题最好重新设计以使用 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>
结果