如何从后面的代码访问UIElement的隐式(非默认)样式?

时间:2017-03-22 11:08:44

标签: c# wpf infragistics

我正在尝试为DataRecordCellArea调整一个Infragistics XamDataGrid的样式,主要基于当前指定的样式(通过ThemeManager,但可能在父元素上)。通常情况下,如果主题的应用方式与系统主题相同,我会使用以下方式执行此操作:

<!-- with xmlns:idp="http://infragistics.com/DataPresenter" -->
<Style 
    TargetType="{x:Type idp:DataRecordCellArea}" 
    BasedOn={StaticResource {x:Type idp:DataRecordCellArea}}
    >
    <!-- Style overrides -->
</Style>

将样式作为资源注入XamDataGrid,希望根据BasedOn属性选择隐式样式。但是,这不是正在发生的事情:使用这种方法,我得到XamlParseExceptionStaticResource相关的无法找到资源 - 即没有基于事物的风格

&#34;伟大&#34;,你可能会想,&#34;只是摆脱基于它的工作。&#34;这是正确的,除非这样做是空的样式显然会影响控件的外观,因为它偏离了主题提供的内容。

我想要的解决方案是一个自定义MarkupExtension,它采用一个名为FrameworkElement和一个目标类型,并试图找到正在使用的隐式样式,我将创建一个目标类型的实例作为上下文提供对象。如果结果是默认样式(甚至是空值),那么就这样吧。在开始使用样式时,这应该是安全的,因为我不需要响应上下文中的更改,只需在构造样式时获取值。我想。

然而,我无法解决的问题是,如果没有找到实际样式属性的显式值,那么如何检索元素的IMPLICIT样式。 Finding the default style似乎很容易,但由于Application.Current.FindResource()方法没有可提供的上下文,我相信这相当于将BasedOn属性留空。相反,如果我只是获得var implicit = Context.Resources.Contains(TargetType) ? Context.Resources[TargetType] : null;,我希望得到假空值,然后我希望只捕获那些ResourceDictionary的明确成员及其MergedDictionaries集合的样式。

还有可能进一步复杂化:即我实际想要替换的样式可能不仅仅是键入类型。例如,假设主题可以将相同的对象用于多个目的,并且每个目的都具有特定的键名称,然后在为父对象配置ControlTemplate期间分配样式,即

<Style TargetType={XamDataGridOrSomeUnknownChildOfXamDataGrid}>
    <Style.Setters>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate>
                    <ControlTemplate.Resources>
                        <Style TargetType="{TheTypeICareAbout}" x:Key="SomeActualKeyedValue" BasedOn="{StaticResource SomeThemeStyleOrKeyToTheDefaultOne}">
                        <!-- Style definition -->
                        </Style>
                    </ControlTemplate.Resources>
                    ...
                    <TheTypeICareAbout Style="{StaticResource SomeActualKeyedValue}" />
                    ...
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style.Setters>
</Style>

目前,我希望这不是正在发生的事情,但至少有一些证据表明它可能会发生。如果有人知道在渲染ControlTemplate时挂钩并覆盖THAT样式的方法,这也会回答我的问题 - 可能比找到隐式样式更好(因为那时我并没有真正覆盖隐含的样式)。

1 个答案:

答案 0 :(得分:0)

我最终采用的方法(忽略现在的复杂情况)是编写一个标记扩展,它为上下文和目标类型提供了FrameworkElement。从那里可以看出,所有FrameworkElements都有一个FindResource()方法(不仅仅是Application),因此只需调用FindResource就可以了,因为它与上下文对象有关。

结果是xaml看起来像:

<Style 
    TargetType={x:Type TheTypeIWant} 
    BasedOn={BasedOnWithContext Context={x:ref NameOfContextProvidingObject},TargetType={x:Type TheTypeIWant}} 
    />

...和C#看起来像:

public class BasedOnWithContextExtension : MarkupExtension 
{
    public BasedOnWIthContextExtension() 
    {
    }

    public DependencyObject Context {get; set;} 

    public Type TargetType {get; set;} 

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this.Context?.FindResource(this.TargetType) as Style;
    }
}

(注意以上是我的解决方案的近似值,因为我没有代码库,并且暂时没有尝试编译它,但它应该提供一个关于有效方法的公平想法。)

这将很好地评估创建样式的时间点,找到隐式样式,并将其基于该样式。它找不到具有未知(或已知)键的样式并替换它们(根据复杂的情况)。