【问题标题】:Disable wpf resource inheritance禁用 wpf 资源继承
【发布时间】:2018-10-19 15:11:29
【问题描述】:

出于性能和隔离原因,我有一个使用跨进程通信的应用程序,并利用System.AddIn.Pipeline.FrameworkElementAdapters.ContractToViewAdapter()System.AddIn.Pipeline.FrameworkElementAdapters.ViewToContractAdapter() 方法将GUI 控件从插件进程传输到主机进程。

插件 GUI 控件主要是 Microsoft 提供的控件,支持重新托管的 Microsoft Workflow Foundation 界面。其中许多在其 xaml 定义中具有硬编码的颜色和画笔,并且不容易重新命名。

我支持两种不同的主机应用程序。其中一个通过应用程序级 ResourceDictionary 进行了广泛的主题化,另一个不进行任何自定义主题化。

在没有自定义主题的应用程序中,控件因此显示

但在具有自定义主题的应用程序中,它看起来像这样

它从宿主应用程序中提取了一些主题,但由于 Microsoft 控制了大部分颜色的硬编码,因此它不完整并且看起来很糟糕。

我使用 Snoop 来查找主题应用程序强加到这些控件上的画笔和颜色,并据此制作了具有正确颜色的资源字典。

<ResourceDictionary 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options" 
    xmlns:s="clr-namespace:System;assembly=mscorlib">

    <Color x:Key="aC03">#FF000000</Color>
    <Color x:Key="aC09">#FFFFFFFF</Color>
    <Color x:Key="aC10">#FF858C9D</Color>
    <Color x:Key="aC11">#FF000000</Color>
    <Color x:Key="aC13">#FF8C9097</Color>
    <Color x:Key="aC14">#FFFFFFFF</Color>
    <Color x:Key="aC15">#FF777D87</Color>
    <Color x:Key="aC16">#FF6E7582</Color>
    <Color x:Key="aC17">#FFE9ECEE</Color>
    <Color x:Key="aC20">#FF000000</Color>
    <Color x:Key="aC21">#FF000000</Color>

    <GradientStopCollection x:Key="aG01">
        <GradientStop Offset="0.00" Color="{StaticResource aC10}" />
        <GradientStop Offset="0.10" Color="{StaticResource aC13}" />
        <GradientStop Offset="0.49" Color="{StaticResource aC15}" />
        <GradientStop Offset="0.50" Color="{StaticResource aC16}" />
        <GradientStop Offset="1.00" Color="{StaticResource aC16}" />
    </GradientStopCollection>

    <SolidColorBrush x:Key="ControlTextBrush" PresentationOptions:Freeze="true" Color="{StaticResource aC03}" />
    <SolidColorBrush x:Key="ControlBrush" PresentationOptions:Freeze="true" Color="{StaticResource aC14}" />
    <SolidColorBrush x:Key="TextBox_Default_Layer1" PresentationOptions:Freeze="true" Color="{StaticResource aC14}" />
    <SolidColorBrush x:Key="TextBox_Default_Layer2" PresentationOptions:Freeze="true" Color="{StaticResource aC21}" />
    <SolidColorBrush x:Key="TextBox_Default_Layer3" PresentationOptions:Freeze="true" Color="{StaticResource aC11}" />
    <SolidColorBrush x:Key="ComboBox_Default_Layer2" PresentationOptions:Freeze="true" Color="{StaticResource aC20}" />
    <LinearGradientBrush x:Key="ComboBox_Default_Layer3" PresentationOptions:Freeze="true" GradientStops="{StaticResource aG01}" StartPoint="0,0" EndPoint="0,1" />
    <SolidColorBrush x:Key="ComboBox_Default_Text" PresentationOptions:Freeze="true" Color="{StaticResource aC03}" />
    <SolidColorBrush x:Key="WindowBrush" PresentationOptions:Freeze="true" Color="{StaticResource aC17}" />
    <SolidColorBrush x:Key="ContextMenu_Layer1" PresentationOptions:Freeze="true" Color="{StaticResource aC09}" />
</ResourceDictionary>

如果我将此资源字典应用到重新托管的根控件或该控件及其所有子控件,它看起来像这样

所以即使覆盖资源似乎也不够。

有没有办法抑制/防止/禁用资源继承,或者我是否需要覆盖影响我的控件的每个资源(颜色、画笔、样式、模板等)?

编辑:请求了样式覆盖代码。我已经测试了在 Loaded 事件和 Initialized 事件(单独,而不是一起)上运行以下内容,并在 GUI 线程和任务中运行。在加载的事件上调用它会产生一些变化,在初始化的事件上调用它不会

    var resources = new ResourceDictionary { Source = new Uri("pack://application:,,,/WorkflowRemoting;component/Host/ResourceOverride.xaml") };

    Action<DependencyObject, ResourceDictionary> 
        SetResources = null;
    SetResources = (element, dictionary) =>
    {
        DependencyObject[]
            children = null;
#if runInTask
        Dispatcher.Invoke(() =>
        {
#endif
            var nChildren = VisualTreeHelper.GetChildrenCount(element);
            children = Enumerable.Range(0, nChildren).Select(x => VisualTreeHelper.GetChild(element, x)).ToArray();
#if runInTask
        });
#endif
        foreach (var child in children)
        {
#if runInTask
            Dispatcher.Invoke(() =>
            {
#endif
                var fe = child as FrameworkElement;
                if (fe != null)

                    if (this.Resources == null)
                        fe.Resources = dictionary;
                    else
                        fe.Resources.MergedDictionaries.Add(dictionary);
#if runInTask
            });
#endif
            SetResources(child, dictionary);
        }
    };

#if runInTask
    Task.Run(() =>
    {
#endif
        SetResources(this, resources);
#if runInTask
    });
#endif

【问题讨论】:

  • 我已编辑问题以显示该部分代码、我如何尝试执行它以及结果
  • 为什么不使用 xaml 来覆盖资源?
  • 我的印象是设置资源字典实际上是一回事。无论如何,这只是我可以编辑 xaml 的控件的一个选项。大多数控件都是 System.Activities.Presentation 的一部分,微软在设计它们时并没有考虑到自定义

标签: c# wpf workflow-foundation


【解决方案1】:

如果您要显示控件,只需将每个控件的样式清零即可:

<Button Style="{x:Null}" Content="Press me"/>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多