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

时间:2013-08-09 11:48:17

标签: wpf

我来找你,因为我对控制造型感到头疼几个小时。 通过为usercontrol定义样式,它不起作用!

我的usercontrol声明:

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

我想申请的格式:

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

为什么它不能与Background属性一起使用,尽管它与Visibility属性一起使用! 我尝试使用TargetType = FrameworkElement,没有效果....

我的usercontrol是一个数字文本框,它定义了自己的样式:

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

非常感谢你的帮助。

4 个答案:

答案 0 :(得分:2)

我想我知道你在做什么......

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

这解释了为什么Visibility适合您,因为该属性未在ResourceDictionary中的Style中设置。

您应该将Style设置为StaticResource,然后将该样式的任何后续样式作为基础。这基本上是Sheridan所建议的,但你应该用一个关键名称来引用Style ......

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

调整风格......

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

答案 1 :(得分:1)

我刚用Style进行了快速测试,一切正常。要使WPF Style正常工作,您需要做几件事。首先,您的自定义控件需要覆盖其静态构造函数中的DefaultStyleKey

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

    ...
}

第二个问题是,您需要在程序集中的特定位置定义NumericTextBox的默认Style才能获取它。标准位置位于Project\Themes\Generic.xaml

如果您仍然在努力创建自定义WPF控件并设置样式,请参阅以下CodeProject article

bgcode的评论

TDefaultStyleKey,它仍按照您的建议实施。 第二个是我的NumericTextBox的样式作为resourcedictionary实现到另一个文件中,但我在构造函数中加载它:

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

我认为这也是一种很好的方式,不是吗?

Abe Heidebrecht的回应

没有。不要那样做。如果您想在单独的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>

如果您确实不希望使用generic.xaml,则可以将字典合并到App.Resources中的app.xaml。你之所以喜欢把它放在generic.xaml中的原因是,如果你在某个时候将这个控件放在一个控件的程序集中,你将需要generic.xaml中,或者WPF不知道在哪里可以找到默认的Style。养成以正确的方式做这件事的习惯会更好。

答案 2 :(得分:1)

您在此处定义的样式

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

被ResourceDictionary

中定义的样式覆盖

如果您尝试:

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

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

答案 3 :(得分:-1)

尝试这个怎么样:

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

我不确定你的XML命名空间是否会匹配,但我们的想法是基本上对WPF说'这种风格是基于这种类型的默认风格'