【问题标题】:Why I can't override Property in control when Style Property is set?为什么在设置样式属性时无法覆盖控制中的属性?
【发布时间】:2014-05-22 10:55:45
【问题描述】:

我创建了自定义 TextBlock 控件:

[ContentProperty("Text")]
[TemplatePart(Name = TextBlockName, Type = typeof(TextBlock))]
public class CustomTextBlock : Control
{
    #region Constraints

    private const string TextBlockName = "Container";

    #endregion

    #region Private Fields

    private TextBlock _tbValue;

    #endregion

    #region TextProperty Depenancy Property

    public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
        "Text",
        typeof(string),
        typeof(CustomTextBlock),
        new PropertyMetadata(null, TextChangedCallback));

    public string Text
    {
        get { return (string)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }

    private static void TextChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
    {
        var control = (CustomTextBlock)dependencyObject;
        control.UpdateText();
    }

    #endregion

    #region TextWrapping Dependency Property

    public static readonly DependencyProperty TextWrappingProperty = DependencyProperty.Register(
        "TextWrapping",
        typeof(TextWrapping),
        typeof(CustomTextBlock), null);


    public TextWrapping TextWrapping
    {
        get { return (TextWrapping)GetValue(TextWrappingProperty); }
        set { SetValue(TextWrappingProperty, value); }
    }

    #endregion

    public static readonly DependencyProperty TextStyleProperty =
   DependencyProperty.Register("TextStyle", typeof(Style), typeof(CustomTextBlock), new PropertyMetadata(null));

    public Style TextStyle
    {
        get { return (Style)GetValue(TextStyleProperty); }
        set { SetValue(TextStyleProperty, value); }
    }

    #region TextAlignment Dependency Property

    public static readonly DependencyProperty TextAlignmentProperty = DependencyProperty.Register(
        "TextAlignment",
        typeof(TextAlignment),
        typeof(CustomTextBlock),
        null);


    public TextAlignment TextAlignment
    {
        get { return (TextAlignment)GetValue(TextAlignmentProperty); }
        set { SetValue(TextAlignmentProperty, value); }
    }

    #endregion

    #region Constructor

    public CustomTextBlock()
    {
        DefaultStyleKey = typeof(CustomTextBlock);
    }

    #endregion

    #region Methods

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        _tbValue = GetTemplateChild(TextBlockName) as TextBlock;
        UpdateText();
        UpdateTextStyle();
    }

    private void UpdateTextStyle()
    {
        if (_tbValue != null && TextStyle != null)
            _tbValue.Style = TextStyle;
    }

    private void UpdateText()
    {
        if (this._tbValue != null)
        {
            this._tbValue.Inlines.Clear();
            if (!String.IsNullOrEmpty(this.Text))
            {
                // some stuff
            }
        }
    }

    #endregion
} 

模板如下:

<Style  TargetType="customControls:CustomTextBlock" >
    <Setter Property="Foreground" Value="{StaticResource DefaultFontBrush}"/>
    <Setter Property="FontSize" Value="30"/>
    <Setter Property="FontFamily" Value="{StaticResource DefaultFont}"/>
    <Setter Property="TextWrapping" Value="NoWrap"/>
    <Setter Property="TextAlignment" Value="Left"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="customControls:CustomTextBlock">
                <TextBlock Name="Container"
                           TextWrapping="{TemplateBinding TextWrapping}"
                           TextAlignment="{TemplateBinding TextAlignment}"/>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

一切都很好,但是当我尝试使用 TextStyle 和其他属性时出现问题。 我的期望是这些特定属性会覆盖 TextStyle 中的属性,但事实并非如此。

 <control:CustomTextBlock 
               TextStyle="{StaticResource StyleWithYellowForeground}"
                Foreground="Red"
                FontSize="20"
                Text="Sample text"
                />

样式“StyleWithYellowForeground”有一些设置器,但它的前景设置为黄色。在我的声明中,我将前景设置为红色,因为我想以这种样式覆盖“前景”,但它不起作用(它仍然具有黄色前景)。

你知道如何解决这个问题吗?


我的意思是实现声明样式的某些优先级(从最重要的覆盖其他样式):

1)控件声明中设置的内联属性 2)控件声明中设置的TextStyle属性 3)默认控件样式中设置的默认属性

【问题讨论】:

    标签: wpf xaml windows-phone-7 windows-phone-8 windows-phone


    【解决方案1】:

    问题是设置 TextStyle 会改变 TextBlock 本身的 Style,因此 TextBlock 本身将 Foreground 设置为 Yellow。更改整个控件的 Foreground 不会对此产生影响,因为它只是 TextBlock 的一个容器。控件的样式会覆盖其容器中的值。要更改 Foreground,您需要更改实际 TextBlock 的 Foreground 属性。

    你想达到什么目的?也许它可以以某种方式简化...您可以使整个控件的前景覆盖 TextBlock 的前景,但这似乎不是一个好主意。

    编辑

    这里有两种解决方法:

    • 添加一个属性 ForegroundOverride,一旦设置为某个值,设置 TextBlock 的 Foreground 属性,该属性将覆盖样式中的值。如果未设置,将使用 Style 中的值。

    • 像这样设置TextStyle:

      <local:CustomTextBlock.TextStyle>
          <Style TargetType="TextBlock" BasedOn="{StaticResource StyleWithYellowForeground}">
              <Setter Property="Foreground" Value="Red" />
          </Style>
      </local:CustomTextBlock.TextStyle>
      

      这样,您可以重复使用您想要的样式,也可以覆盖您想要的属性。它不像简单地设置 Foreground 那样酷,但它可以正常工作。

    编辑 2

    也许您可以尝试使用默认的 TextBlock(所有样式和内联属性都可以使用),并使用附加/混合行为来实现您想要的?以下是关于它们的一些信息:http://www.jayway.com/2013/03/20/behaviors-in-wpf-introduction/

    【讨论】:

    • 你说对了一部分。如果我从声明中删除 TextStyle,则前景应用作为内部模板的 TextBlock。所以即使现在也可以工作。根据您的回答,如果我在 CustomTextBlock 模板中的 TextBlock 内设置 Foreground="{TemplateBinding Foreground}" 它应该可以工作。但又一次。它无法正常工作。因为那时我的样式的 Foreground 将不会被应用,因为在 CustomTextBlock 样式中定义为 Setter 的默认值。还有其他想法吗?
    • 我从没说过这行得通。 :) 不是因为这样做会设置 TextBlock 的 Foreground 属性,它只会覆盖 TextBlock 样式中的任何内容。要使两者都起作用,它将更加复杂。你真的需要传递风格吗?我正在尝试另一种解决方案,但目前没有什么好的和简单的办法。
    • 是的,这里需要样式,我希望我的控件表现得像其他控件一样
    • 我修改了答案以添加一些想法
    • 之前我覆盖了像 Foreground 这样的 DP 属性(它是我想要覆盖的许多其他属性之一),但没有按我的意愿工作。在我的情况下,您的第一个建议很糟糕,因为我想重用我已经为 TextBlock 定义的很多样式。第二个也不是最好的,因为我仍然想内联更改一些属性,而不是创建其他样式只是为了覆盖其他样式的属性。必须有一些更简单的解决方案
    猜你喜欢
    • 2016-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-06
    • 1970-01-01
    • 1970-01-01
    • 2013-06-10
    • 2010-12-11
    相关资源
    最近更新 更多