简体   繁体   English

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

[英]How can I access the implicit (not default) style for a UIElement from code behind?

I am trying to tweak a style for an Infragistics DataRecordCellArea for a XamDataGrid to be largely based on the currently assigned style (via ThemeManager, but potentially on a parent element). 我试图为Infragistics DataRecordCellArea调整一个XamDataGrid的样式,主要基于当前分配的样式(通过ThemeManager,但可能在父元素上)。 Normally, if the theme were being applied in the same way as the system themes, I would do this using something like: 通常情况下,如果主题的应用方式与系统主题相同,我会使用以下方式执行此操作:

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

with the style being injected as a resource on the XamDataGrid , in the hope that the implicit style would be picked up based on the BasedOn attribute. 将样式作为资源注入XamDataGrid ,希望根据BasedOn属性拾取隐式样式。 However, this isn't what's happening: using this approach, I get a XamlParseException related to StaticResource being unable to find the resource - ie there is no style to base things on. 然而,这不是正在发生的事情:使用这种方法,我得到一个与StaticResource相关的XamlParseException无法找到资源 - 即没有基于事物的样式。

"Great", you might think, "Just get rid of the based on and it'll work." “好极了”,你可能会想,“只要摆脱基础,它就会起作用。” This would be true except that doing so with an empty style clearly DOES affect the control's appearance as a deviation from what the theme provides. 这样做是正确的,除了这样做,空的样式显然会影响控件的外观,因为它偏离了主题提供的内容。

My intended solution is a custom MarkupExtension that takes a named FrameworkElement and a target type and attempts to find the implicit style that WOULD be in use were I to create an instance of the target type as a child of the context-providing object. 我想要的解决方案是一个自定义MarkupExtension,它接受一个命名的FrameworkElement和一个目标类型,并试图找到正在使用的隐式样式,我将创建一个目标类型的实例作为上下文提供对象的子项。 If that turns out to be the default style (or even a null value), then so be it. 如果结果是默认样式(甚至是空值),那么就这样吧。 This should be safe for sealing when the style starts to be used, too, because I do not need to respond to changes in context, just get the value at the point when the style is constructed. 在开始使用样式时,这应该是安全的,因为我不需要响应上下文中的更改,只需在构造样式时获取值。 I think. 我认为。

However, what I can't work out is HOW to retrieve the IMPLICIT style for an element when no explicit value is found for the actual style property. 但是,我无法解决的问题是,如果没有找到实际样式属性的显式值,那么如何检索元素的IMPLICIT样式。 Finding the default style seems easy enough, but since there is no context providable to the Application.Current.FindResource() method, I am convinced this will be the equivalent of leaving the BasedOn attribute blank. 找到默认样式似乎很容易,但由于Application.Current.FindResource()方法没有可提供的上下文,我相信这将等同于将BasedOn属性留空。 Conversely, I expect to get false nulls if I simply get var implicit = Context.Resources.Contains(TargetType) ? Context.Resources[TargetType] : null; 相反,如果我只是得到var implicit = Context.Resources.Contains(TargetType) ? Context.Resources[TargetType] : null; ,我希望得到假空值var implicit = Context.Resources.Contains(TargetType) ? Context.Resources[TargetType] : null; var implicit = Context.Resources.Contains(TargetType) ? Context.Resources[TargetType] : null; , then I expect to only capture styles that are explicit members of that ResourceDictionary and its collection of MergedDictionaries . ,然后我希望只捕获那些ResourceDictionary明确成员及其MergedDictionaries集合的样式。

There is a possibility of a further complication, too: namely the possibility that the style I actually want to replace may NOT be keyed only with the type. 还有可能进一步复杂化:即我实际想要替换的样式可能不仅仅与类型键入。 For instance, imagine that the theme may use the same object for multiple purposes, and each of those purposes has a specific key name, with the style then assigned during the ControlTemplate being configured for the parent object, ie 例如,假设主题可以将相同的对象用于多个目的,并且每个目的都具有特定的键名称,然后在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>

For the time being, I am hoping that this is NOT what is happening, but there is at least some evidence that indicates it might be. 目前,我希望这不是正在发生的事情,但至少有一些证据表明它可能是。 If anyone knows of a way to hook onto and override THAT style when the ControlTemplate is rendered, this would also answer my problem - possibly better than finding the implicit style (because then I'm not actually overriding an implicit style). 如果有人知道在渲染ControlTemplate时挂钩并覆盖THAT样式的方法,这也会回答我的问题 - 可能比找到隐式样式更好(因为那时我实际上并没有覆盖隐式样式)。

The approach I ended up taking (ignoring the complicating case for now) was to write a markup extension that took a FrameworkElement for context and a target type. 我最终采用的方法(暂时忽略了复杂的情况)是编写一个标记扩展,它为上下文和目标类型提供了FrameworkElement。 From there, it turns out that all FrameworkElements have a FindResource() method (not just the Application), so it was pretty straightforward to just call FindResource as it pertained to the context object. 从那里,事实证明所有FrameworkElements都有一个FindResource()方法(不仅仅是Application),因此只需调用FindResource就可以了,因为它与上下文对象有关。

The result is xaml that looks something like: 结果是xaml看起来像:

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

... and C# that looks something like: ...和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;
    }
}

(NB the above is an approximation of my solution, since I don't have the code-base to hand, and haven't tried compiling it for now, but it should provide a fair idea as to the approach that worked.) (注意,以上是我的解决方案的近似值,因为我没有代码库,现在还没有尝试过编译它,但它应该提供一个关于有效方法的公平想法。)

This evaluates nicely at the point when the style would be created, finds the implicit style, and bases it off that. 这将很好地评估创建样式时的点,找到隐式样式,并将其基于该样式。 It doesn't find styles with an unknown (or known) key and replace them though (per the complicating case). 它找不到具有未知(或已知)键的样式并替换它们(根据复杂情况)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM