wpf - Style BasedOn 的动态资源

标签 wpf styles

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

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

当 menuitem 的使用没有指定样式时,这很有效。这在许多情况下是不现实的,因为没有样式就无法绑定(bind) ItemsSource 生成的子项。例如:
<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 上的所有其他帖子都说你只需要这样做......
<Style TargetType="MenuItem" BasedOn="{StaticResource {x:Type MenuItem}}">
    <!-- Your overrides -->
</Style>

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

所以我的问题...

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

最佳答案

终于想出了一个解决方案DynamicResouce对于 Style.BasedOn使用 AttachedDependencyProperty .

这是 ItemsControl.ItemContainerStyle 的修复程序(可以轻松修改更改 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 的修改版本而是在我对另一篇文章的回答中:
Setting a local implicit style different from theme-style / alternative to BasedOn DynamicResource

关于wpf - Style BasedOn 的动态资源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9490264/

相关文章:

c# - 当 DataGrid 嵌套在分组的 DataGrid 中时,相对列宽不起作用

WPF - 将图像水平绑定(bind)到 ListView

c# - 绑定(bind)数据网格后,项目集合必须为空

javascript - 如何更改表单中标签的颜色?

styles - JavaFX HTML 样式(或等效)标签

php - CSS Div 标签不起作用

Jquery .style 未定义

c# - BindingOperations.GetBindingExpression 在 WPF 中返回 null

javascript - 以编程方式决定在 javascript 中修改哪个样式属性

c# - 使用转换器 WPF 绑定(bind)来自另一个 cs 文件的属性