基于样式的动态资源 [英] DynamicResource for Style BasedOn

查看:26
本文介绍了基于样式的动态资源的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

构建一个具有自定义高对比度"主题的应用程序,供户外使用,可以在运行时打开和关闭.通过合并和取消合并包含如下样式的资源字典,这可以正常工作...

Building an application that has a custom 'High Contrast' theme for outdoor use that can be toggled on and off during runtime. This works fine by merging and un-merging a resource dictionary that contains styles like below...

<Style x:Key="{x:Type MenuItem}" TargetType="{x:Type MenuItem}">
    <Setter Property="OverridesDefaultStyle" Value="true"/>
    <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
    <Setter Property="Template" Value="{StaticResource Theme_MenuItemTemplate}"/>
</Style>

当菜单项的使用没有指定样式时,这很有效.尽管在许多情况下这并不现实,因为无法绑定 ItemsSource 生成的没有样式的子项.例如:

This works great when the usage of a menuitem doesn't specify a style. This isn't realistic though for many situations since there is no way to bind ItemsSource generated children without Styles. For example:

<ContextMenu.ItemContainerStyle>
    <Style TargetType="MenuItem">
        <Setter Property="Header" Value="{Binding Path=Name}"/>
        <Setter Property="IsCheckable" Value="True"/>
        <Setter Property="IsChecked" Value="{Binding Path=Checked}"/>
        <EventSetter Event="Checked" Handler="HistoryItem_Checked"/>
    </Style>
</ContextMenu.ItemContainerStyle>

StackOverflow 上的所有其他帖子都说你只需要这样做......

Every other post on StackOverflow says you just need to do this...

<Style TargetType="MenuItem" BasedOn="{StaticResource {x:Type MenuItem}}">
    <!-- Your overrides -->
</Style>

但这对我的情况不起作用,因为我的 BasedOn 可以并且会在运行时更改(当然,您不能在 BasedOn 属性上使用 DynamicResource 扩展).在我的应用程序中执行此操作目前会导致在加载控件时覆盖的控件卡住其样式,而其他所有控件都正确切换而无需重新加载.

But this doesn't work for my situation because my BasedOn can and will change at runtime (and of course you can't use DynamicResource extension on the BasedOn property). Doing this in my application currently leads to controls that override getting stuck with their style when the control was loaded while every other control correctly switches without reloading.

所以我的问题...

有没有办法让 DynamicResource 扩展为 BasedOn 工作,或者我可以实施另一种方法/hack 来让它工作吗?

Is there a way to get DynamicResource extension working for BasedOn or is there another method/hack I can implement to get this to work?

推荐答案

终于找到了一个使用 AttachedDependencyPropertyStyle.BasedOnDynamicResouce 解决方案/代码>.

Finally figured out a solution for a DynamicResouce for Style.BasedOn using an AttachedDependencyProperty.

这是 ItemsControl.ItemContainerStyle 的修复(可以轻松修改以更改 FrameworkElement.Style)

Here is the fix for ItemsControl.ItemContainerStyle (can be easily modified to change FrameworkElement.Style)

public class DynamicContainerStyle
{
    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(DynamicContainerStyle), new UIPropertyMetadata(DynamicContainerStyle.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(DynamicContainerStyle), new UIPropertyMetadata(DynamicContainerStyle.StylesChanged));

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

        var Element = (System.Windows.Controls.ItemsControl)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.ItemContainerStyle = 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;
    }
}

这是一个例子...

<!-- xmlns:ap points to the namespace where DynamicContainerStyle class lives -->
<MenuItem Header="Recent" 
    ItemsSource="{Binding Path=RecentFiles}"
    IsEnabled="{Binding RelativeSource={RelativeSource Self}, Path=HasItems}"
    ap:DynamicContainerStyle.BaseStyle="{DynamicResource {x:Type MenuItem}}">
    <ap:DynamicContainerStyle.DerivedStyle>
        <Style TargetType="MenuItem">
            <EventSetter Event="Click"  Handler="RecentFile_Clicked"/>
        </Style>
    </ap:DynamicContainerStyle.DerivedStyle>
    <MenuItem.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding}"/>
        </DataTemplate>
    </MenuItem.ItemTemplate>
</MenuItem>

这是一个修改后的版本,它在我对另一篇文章的回答中设置了 FrameworkElement.Style:设置本地隐式风格不同于主题风格/替代基于动态资源

Here is a modified version that sets the FrameworkElement.Style instead in my answer to another post: Setting a local implicit style different from theme-style / alternative to BasedOn DynamicResource

这篇关于基于样式的动态资源的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆