WPF 样式不适用于已设置样式的 UserControl

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18145994/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 09:24:30  来源:igfitidea点击:

WPF Style is not applied for a UserControl who is already styled

wpf

提问by bgcode

I come to you because I got headaches about control styling for a few hours. By defining a style to the usercontrol, it doesn't work !

我来找你是因为我在几个小时内对控制样式感到头疼。通过为用户控件定义样式,它不起作用!

My usercontrol declaration :

我的用户控件声明:

<uiComponent:NumericTextBox Text="{Binding myProperty}"/>

The style I want to apply to :

我想申请的风格:

<Style TargetType="uiComponent:NumericTextBox">
   <Setter Property="Background" Value="Black"/>
</Style>

Why it doesn't work with the Background property, although it works with the Visibility property ! I tried with TargetType=FrameworkElement, no effect....

为什么它不适用于 Background 属性,尽管它适用于 Visibility 属性!我尝试了 TargetType=FrameworkElement,没有效果....

My usercontrol is a numerictextbox which define its own style like this :

我的用户控件是一个数字文本框,它定义了自己的样式,如下所示:

<ResourceDictionary
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:mwt="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
  xmlns:l="clr-namespace:LSX.Space.PropertyUI.NumericTextBox">

    <SolidColorBrush x:Key="CustomTextBox_Background" Color="White" />
    <SolidColorBrush x:Key="CustomTextBox_Foreground" Color="Black" />
    <LinearGradientBrush x:Key="CustomTextBox_Border" StartPoint="0,0" EndPoint="0,1">
        <GradientStop Color="#FFABADB3" Offset="0.05" />
        <GradientStop Color="#FFE2E3EA" Offset="0.07" />
        <GradientStop Color="#FFE3E9EF" Offset="1" />
    </LinearGradientBrush>

    <Style x:Key="{x:Type l:NumericTextBox}" TargetType="{x:Type l:NumericTextBox}">
        <Setter Property="Background" Value="{StaticResource CustomTextBox_Background}" />
        <Setter Property="BorderBrush" Value="{StaticResource CustomTextBox_Border}" />
        <Setter Property="Foreground" Value="{StaticResource CustomTextBox_Foreground}" />
        <Setter Property="BorderThickness" Value="1" />
        <Setter Property="SnapsToDevicePixels" Value="True" />
        <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type l:NumericTextBox}">
                    <Border x:Name="Border"
                      Background="{TemplateBinding Background}"
                      BorderBrush="{TemplateBinding BorderBrush}"
                      BorderThickness="{TemplateBinding BorderThickness}">
                        <Grid x:Name="LayoutGrid">
                            <ScrollViewer Margin="2" x:Name="PART_ContentHost" />
                        </Grid>
                    </Border>
                    <ControlTemplate.Triggers>
                        <!--Message validation des erreurs-->
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="HasText" Value="True" />
                                <Condition Property="Validation.HasError" Value="True" />
                            </MultiTrigger.Conditions>
                            <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path= TextError}"/>
                            <Setter Property="Validation.ErrorTemplate">
                                <Setter.Value>
                                    <ControlTemplate>
                                        <DockPanel LastChildFill="True">
                                            <Image x:Name="ValidationIcon" DockPanel.Dock="Left" Stretch="None" Width="15" Height="15" Source="pack://application:,,,/LS.Net.Telcom.Space.PropertyUI;component/Images/validationError.png" />
                                            <Border BorderBrush="Red" BorderThickness="1">
                                                <AdornedElementPlaceholder />
                                            </Border>
                                        </DockPanel>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </MultiTrigger>

                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

Many thanks for your help.

非常感谢您的帮助。

采纳答案by Abe Heidebrecht

I just ran a quick test with your Styles, and everything is working properly. For WPF Styles to work properly, there are a couple of things you need to do however. The first is that your custom control needs to override the DefaultStyleKeyin its static constructor:

我刚刚对您的Styles进行了快速测试,一切正常。为了让 WPFStyle正常工作,您需要做一些事情。首先是您的自定义控件需要覆盖DefaultStyleKey其静态构造函数中的 :

public class NumericTextBox : TextBox
{
    static NumericTextBox()
    {
        DefaultStyleKeyProperty.OverrideMetadata(
            typeof(NumericTextBox),
            new FrameworkPropertyMetadata(typeof(NumericTextBox)));
    }

    ...
}

The second is that your NumericTextBox's default Styleneeds to be defined at a specific location in your assembly for it to be picked up. The standard location is at Project\Themes\Generic.xaml.

第二个是您NumericTextBox的默认值Style需要在您的程序集中的特定位置定义才能被拾取。标准位置在Project\Themes\Generic.xaml

If you're still struggling with how to create custom WPF controls and styling them, here is a great introductory CodeProject article.

如果您仍在为如何创建自定义 WPF 控件并为其设置样式而苦苦挣扎,这里有一篇很棒的CodeProject介绍性文章

bgcode's comment

bgcode 的评论

TDefaultStyleKey, it is still implemented as you propose. The second is that my NumericTextBox's style is implemented as a resourcedictionary into an other file, but I load it in constructor like that :

TDefaultStyleKey,它仍然按照您的建议实施。第二个是我的 NumericTextBox 样式作为资源字典实现到另一个文件中,但我将它加载到构造函数中,如下所示:

    public NumericTextBox ()
        : base()
    {
        ResourceDictionary res = Application.LoadComponent(new Uri("/MyAssemblyName;component/NumericTextBox/NumericTextBoxStyle.xaml", UriKind.RelativeOrAbsolute)) as ResourceDictionary;
        if(res != null)
            this.Resources = res;
    }

I think that is a good way to do too, isn't it?

我认为这也是一个很好的方法,不是吗?

Abe Heidebrecht's response

安倍海德布莱希特的回应

No. Don't do that. If you want to define the default Stylein a separate ResourceDictionary, do so. Just merge it into the generic.xaml:

不,不要那样做。如果要Style在单独的 中定义默认值ResourceDictionary,请这样做。只需将其合并到 generic.xaml 中:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="MyAssemblyName;component/NumericTextBox/NumericTextBoxStyle.xaml" />
    </ResourceDictionary.MergedDictionaries>

</ResourceDictionary>

If you reallydon't want to have a generic.xaml, you can merge the dictionary into the App.Resourcesin your app.xaml. The reason why you'd prefer to put it in generic.xamlis that if at some point you put this control in a control's assembly, you will needit in generic.xaml, or WPF won't know where to find the default Style. It is better to get in the habit of doing it the right way.

如果你真的不想有一个 generic.xaml,你可以将字典合并到你的 .xaml 文件App.Resourcesapp.xaml。您更愿意将其放入的原因generic.xaml是,如果在某个时候将此控件放入控件的程序集中,您将需要generic.xaml,否则 WPF 将不知道在哪里可以找到默认的Style. 最好养成以正确方式做事的习惯。

回答by Nick

I think I see what you're doing...

我想我明白你在做什么...

You're setting your Style in your ResourceDictionary and then setting the Style again somewhere else. So, your ResourceDictionary is loading the Background in your Style so it overrides what you're setting elsewhere.

您正在 ResourceDictionary 中设置样式,然后在其他地方再次设置样式。因此,您的 ResourceDictionary 正在加载您的样式中的背景,因此它会覆盖您在其他地方设置的内容。

This explains why Visibility works for you because that property is not being set in the Style in your ResourceDictionary.

这解释了为什么 Visibility 对您有用,因为该属性没有在您的 ResourceDictionary 的 Style 中设置。

You should set the Style as a StaticResource and then base any later styles off of that Style. This is basically what Sheridan suggested but you should reference the Style by a key name...

您应该将 Style 设置为 StaticResource,然后基于该 Style 的任何后续样式。这基本上是 Sheridan 建议的,但您应该通过键名来引用样式...

<Style x:Key="NumericBoxStyle" TargetType="{x:Type l:NumericTextBox}">
    <Setter Property="Background" Value="{StaticResource CustomTextBox_Background}" />
    <Setter Property="BorderBrush" Value="{StaticResource CustomTextBox_Border}" />
    <Setter Property="Foreground" Value="{StaticResource CustomTextBox_Foreground}" />
    <Setter Property="BorderThickness" Value="1" />
    <Setter Property="SnapsToDevicePixels" Value="True" />
    <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type l:NumericTextBox}">
                <Border x:Name="Border"
                  Background="{TemplateBinding Background}"
                  BorderBrush="{TemplateBinding BorderBrush}"
                  BorderThickness="{TemplateBinding BorderThickness}">
                    <Grid x:Name="LayoutGrid">
                        <ScrollViewer Margin="2" x:Name="PART_ContentHost" />
                    </Grid>
                </Border>
                <ControlTemplate.Triggers>
                    <!--Message validation des erreurs-->
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="HasText" Value="True" />
                            <Condition Property="Validation.HasError" Value="True" />
                        </MultiTrigger.Conditions>
                        <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path= TextError}"/>
                        <Setter Property="Validation.ErrorTemplate">
                            <Setter.Value>
                                <ControlTemplate>
                                    <DockPanel LastChildFill="True">
                                        <Image x:Name="ValidationIcon" DockPanel.Dock="Left" Stretch="None" Width="15" Height="15" Source="pack://application:,,,/LS.Net.Telcom.Space.PropertyUI;component/Images/validationError.png" />
                                        <Border BorderBrush="Red" BorderThickness="1">
                                            <AdornedElementPlaceholder />
                                        </Border>
                                    </DockPanel>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </MultiTrigger>

                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

And adjust the style...

并调整样式...

<Style TargetType="uiComponent:NumericTextBox" BaseOn="{StaticResource NumericBoxStyle}">
   <Setter Property="Background" Value="Black"/>
</Style>

回答by franssu

The style you define here

您在此处定义的样式

<Style TargetType="uiComponent:NumericTextBox">
   <Setter Property="Background" Value="Black"/>
</Style>

gets overridden by the style defined in your ResourceDictionary

被 ResourceDictionary 中定义的样式覆盖

If you try :

如果你试试 :

<uiComponent:NumericTextBox Text="{Binding myProperty}">
   <uiComponent:NumericTextBox.Style>
      <Style TargetType="uiComponent:NumericTextBox" BasedOn="{StaticResource {x:Type uiComponent:NumericTextBox}}">
         <Setter Property="Background" Value="Black"/>
      </Style>
   </uiComponent:NumericTextBox.Style>
</uiComponent:NumericTextBox>

.. your background should be set to black.

.. 你的背景应该设置为黑色。

回答by Sheridan

How about trying this:

试试这个怎么样:

<Style TargetType="uiComponent:NumericTextBox" 
    BasedOn="{StaticResource {x:Type l:NumericTextBox}}">
    <Setter Property="Background" Value="Black"/>
</Style>

I'm not sure if your XML namespaces will match up, but the idea is to basically say to WPF, 'this style is based on the default style of this type'

我不确定您的 XML 命名空间是否匹配,但这个想法基本上是对 WPF 说,“这种样式基于这种类型的默认样式”