Wpf 将不同于主题样式/备选方案的本地隐式样式设置为BasedOn DynamicSource

Wpf 将不同于主题样式/备选方案的本地隐式样式设置为BasedOn DynamicSource,wpf,xaml,styles,Wpf,Xaml,Styles,设想一个wpf应用程序,我可以在其中动态更改主题。我通过在应用程序资源级别交换ResourceDictionary来实现这一点。主题资源字典具有为TextBox等定义的隐式样式 现在,我的应用程序中有一个部分,其中TextBox应该具有这种特定样式“非默认TextBoxStyle”,而不是应用程序范围内的隐式样式 我很想这样做(使用DynamicSource,因为主题可以在运行时更改): 不必这样做: 现在为了简化这一点,我有了在StackPanel上设置可继承的附加属性的想法,该属性将

设想一个wpf应用程序,我可以在其中动态更改主题。我通过在应用程序资源级别交换ResourceDictionary来实现这一点。主题资源字典具有为TextBox等定义的隐式样式

现在,我的应用程序中有一个部分,其中TextBox应该具有这种特定样式“非默认TextBoxStyle”,而不是应用程序范围内的隐式样式

我很想这样做(使用DynamicSource,因为主题可以在运行时更改):


不必这样做:


现在为了简化这一点,我有了在StackPanel上设置可继承的附加属性的想法,该属性将在每个子代文本框上设置指定的样式

这是个好主意吗?有更简单的方法吗?我错过什么了吗


这可以归结为:在样式中,BasedOn=“{DynamicResource…}”的替代方案是什么?

我遇到了完全相同的问题,但对于ItemsContainerStyle…所以我几乎按照您所说的做了,并编写了一个附件属性,允许BasedOn使用动态资源

以下是针对您的情况修改的解决方案:

public class DynamicStyle
{
    public static Style GetBaseStyle(DependencyObject obj)
    {
        return (Style)obj.GetValue(BaseStyleProperty);
    }

    public static void SetBaseStyle(DependencyObject obj, Style value)
    {
        obj.SetValue(BaseStyleProperty, value);
    }

    // Using a DependencyProperty as the backing store for BaseStyle.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty BaseStyleProperty =
        DependencyProperty.RegisterAttached("BaseStyle", typeof(Style), typeof(DynamicStyle), new UIPropertyMetadata(DynamicStyle.StylesChanged));

    public static Style GetDerivedStyle(DependencyObject obj)
    {
        return (Style)obj.GetValue(DerivedStyleProperty);
    }

    public static void SetDerivedStyle(DependencyObject obj, Style value)
    {
        obj.SetValue(DerivedStyleProperty, value);
    }

    // Using a DependencyProperty as the backing store for DerivedStyle.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty DerivedStyleProperty =
        DependencyProperty.RegisterAttached("DerivedStyle", typeof(Style), typeof(DynamicStyle), new UIPropertyMetadata(DynamicStyle.StylesChanged));

    private static void StylesChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
    {
        if (!typeof(FrameworkElement).IsAssignableFrom(target.GetType()))
            throw new InvalidCastException("Target must be FrameworkElement");

        var Element = (FrameworkElement)target;

        var Styles = new List<Style>();

        var BaseStyle = GetBaseStyle(target);

        if (BaseStyle != null)
            Styles.Add(BaseStyle);

        var DerivedStyle = GetDerivedStyle(target);

        if (DerivedStyle != null)
            Styles.Add(DerivedStyle);

        Element.Style = MergeStyles(Styles);
    }

    private static Style MergeStyles(ICollection<Style> Styles)
    {
        var NewStyle = new Style();

        foreach (var Style in Styles)
        {
            foreach (var Setter in Style.Setters)
                NewStyle.Setters.Add(Setter);

            foreach (var Trigger in Style.Triggers)
                NewStyle.Triggers.Add(Trigger);
        }

        return NewStyle;
    }
}
公共类动态样式
{
公共静态样式GetBaseStyle(DependencyObject obj)
{
返回(样式)obj.GetValue(BaseStyleProperty);
}
公共静态void SetBaseStyle(DependencyObject对象,样式值)
{
obj.SetValue(BaseStyleProperty,value);
}
//使用DependencyProperty作为BaseStyle的后台存储。这将启用动画、样式设置、绑定等。。。
公共静态只读DependencyProperty BaseStyleProperty=
DependencyProperty.RegisterAttached(“BaseStyle”、typeof(Style)、typeof(DynamicStyle)、新UIPropertyMetadata(DynamicStyle.StylesChanged));
公共静态样式GetDerivedStyle(DependencyObject obj)
{
返回(样式)对象GetValue(DerivedStyleProperty);
}
公共静态void SetDerivedStyle(DependencyObject对象,样式值)
{
对象设置值(DerivedStyleProperty,值);
}
//使用DependencyProperty作为DerivedStyle的后台存储。这将启用动画、样式设置、绑定等。。。
公共静态只读DependencyProperty DerivedStyleProperty=
DependencyProperty.RegisterAttached(“DerivedStyle”、typeof(Style)、typeof(DynamicStyle)、new UIPropertyMetadata(DynamicStyle.StylesChanged));
私有静态void样式更改(DependencyObject目标,DependencyPropertyChangedEventArgs e)
{
if(!typeof(FrameworkElement).IsAssignableFrom(target.GetType()))
抛出新的InvalidCastException(“目标必须是FrameworkElement”);
var元素=(FrameworkElement)目标;
var Styles=新列表();
var BaseStyle=GetBaseStyle(目标);
if(BaseStyle!=null)
添加(BaseStyle);
var-DerivedStyle=GetDerivedStyle(目标);
如果(DerivedStyle!=null)
样式。添加(DerivedStyle);
Element.Style=MergeStyles(样式);
}
专用静态样式合并样式(ICollection样式)
{
var NewStyle=新样式();
foreach(样式中的变量样式)
{
foreach(Style.Setters中的var Setter)
NewStyle.Setters.Add(Setter);
foreach(Style.Triggers中的var触发器)
NewStyle.Triggers.Add(触发器);
}
回归新闻风格;
}
}
下面是它的使用示例:

<!-- xmlns:ap points to the namespace where DynamicStyle class lives -->
<Button ap:DynamicStyle.BaseStyle="{DynamicResource {x:Type Button}}">
    <ap:DynamicStyle.DerivedStyle>
        <Style TargetType="Button">
            <Style.Triggers>
                <MultiDataTrigger>
                    <MultiDataTrigger.Conditions>
                        <Condition Binding="{Binding Path=FirstButtonWarning}" Value="True"/>
                        <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsEnabled}" Value="True"/>
                    </MultiDataTrigger.Conditions>
                    <MultiDataTrigger.Setters>
                        <Setter Property="Background" Value="{DynamicResource WarningBackground}"/>
                        <Setter Property="Foreground" Value="{DynamicResource WarningForeground}"/>
                    </MultiDataTrigger.Setters>
                </MultiDataTrigger>
            </Style.Triggers>
        </Style>
    </ap:DynamicStyle.DerivedStyle>
    <TextBlock Text="Button that changes background and foreground when warning is active"/>
</Button>

它真的需要成为DynamicSource吗?
所以也许会帮助你

如果不是,这里有一个StaticResource的简单示例

App.xaml

<Application.Resources>
        <Style x:Key="myResource" TargetType="Button">
            <Setter Property="Background" Value="Black"/>
            <Setter Property="Foreground" Value="White"/>
        </Style>         
    </Application.Resources>
<Application.Resources>

    <SolidColorBrush  x:Key="background"  Color="Red" />
    <SolidColorBrush  x:Key="foreground"  Color="Blue" />

    <Style x:Key="NonDefaultTextBoxStyle" >
        <Setter Property="TextBox.Background" Value="{DynamicResource background}"/>
        <Setter Property="TextBox.Foreground" Value="{DynamicResource foreground}"/>
    </Style>

</Application.Resources>

我只能鼓励你阅读这个问题!你没有解决我的问题!@MarkusHütter啊,我现在看到你的问题了。嗯,继续我的回答,你应该能够将我的解决方案中附加的Dependencies属性更改为
FrameworkPropertyMetadataOptions。继承
(使用此选项而不是
UIPropertyMetadata
)然后检查元素类型
StylesChanged
函数。附加属性只需在StackPanel元素上写入一次。@MarkusHütter哈哈,是的,我想当我一年多前第一次读到这篇文章时,我只读了粗体部分并试图回答这个问题。我很抱歉。我想知道为什么这是我唯一的问题张贴,人们不阅读问题!主题和问题是否太难理解?回答你:是的,它需要是动态资源,因为我要求“动态更改主题”(第一句)。如果你阅读了你的链接问题,你会注意到,答案和你的答案一样,没有使用动态资源。很抱歉,这没有帮助!@MarkusHütter sorry for阅读得不够透彻。也许你应该将其加粗为眼睛catcher@MarkusH不管我想我的编辑现在会回答你的问题谢谢,这可能确实有效这意味着从改变风格到改变资源的思想转变。我感谢你努力编辑你的答案。+1
<Application.Resources>

    <SolidColorBrush  x:Key="background"  Color="Red" />
    <SolidColorBrush  x:Key="foreground"  Color="Blue" />

    <Style x:Key="NonDefaultTextBoxStyle" >
        <Setter Property="TextBox.Background" Value="{DynamicResource background}"/>
        <Setter Property="TextBox.Foreground" Value="{DynamicResource foreground}"/>
    </Style>

</Application.Resources>
<StackPanel>
    <Button Content="Button" Height="23" Width="75" Click="Button_Click" />

    <StackPanel>
        <StackPanel.Resources>
            <Style   TargetType="{x:Type TextBox}" BasedOn="{StaticResource NonDefaultTextBoxStyle}">
            </Style>
        </StackPanel.Resources>
        <TextBox Text="bliii" Height="23" Width="75" />
        <TextBox Text="blaaa" Height="23" Width="75" />
        <TextBox Text="blubb" Height="23" Width="75" />
    </StackPanel>

</StackPanel>
private void Button_Click(object sender, RoutedEventArgs e)
        {
            this.Resources["background"] = Brushes.Black;
            this.Resources["foreground"] = Brushes.Yellow;
        }