【问题标题】:WPF styling custom controlWPF 样式自定义控件
【发布时间】:2012-10-23 21:57:42
【问题描述】:

我有一个想要设置样式的自定义控件:

它只是一个继承自TextBox和另一个接口的类,接口只是增加了一个额外的属性。

如何将样式应用于此自定义控件,以便在设置只读属性时,背景变为灰色?


public class DionysusTextBox : TextBox, IDionysusControl
  {

    public DionysusTextBox()
    {
      SetStyle();
    }

    #region IDionysusControl Members

    public bool KeepReadOnlyState
    {
      get { return (bool)GetValue(KeepReadOnlyStateProperty); }
      set { SetValue(KeepReadOnlyStateProperty, value); }
    }

    // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty KeepReadOnlyStateProperty =
        DependencyProperty.Register("KeepReadOnlyState", typeof(bool), typeof(DionysusTextBox), new UIPropertyMetadata(true));

    #endregion

    #region Style

    Style styleListBoxItem = new Style(typeof(DionysusTextBox));
    Trigger triggerReadonly = new Trigger { Property = DionysusTextBox.IsReadOnlyProperty, Value = true };

    private void SetStyle()
    {
      triggerReadonly.Setters.Add(new Setter(DionysusTextBox.BackgroundProperty, Brushes.Black));
      this.Triggers.Add(triggerReadonly);
    }

    #endregion


  }

上面是整个类的代码,我使用样式的方式似乎是合适的方式,但是当我将此控件添加到设计器时,我收到以下错误:

Triggers collection members must be of type EventTrigger.

谁能指出我正确的方向?

【问题讨论】:

  • Trigger 只能应用于Style。在你的情况下styleListBoxItem 不是this
  • 这么简单,我改了,不再收到错误,但是样式不起作用,有什么想法吗?
  • 我没有看到你应用了样式。
  • @ChrisjanL 尝试设置 this.Style = styleListBoxItem;您是否有理由不只在 XAML 中定义样式?
  • @AndyB,控件只是一个.cs文件。没有xml。我希望将样式放在我的通用资源字典中,但它无权访问命名空间。

标签: c# wpf


【解决方案1】:

你可以重新定义依赖属性的默认行为,特别是你可以定义PropertyChangedCallbacks:

public class DionysusTextBox : TextBox, IDionysusControl
{
    static DionysusTextBox()
    {   
        //For the IsReadOnly dependency property    
        IsReadOnlyProperty.OverrideMetadata(
            //On the type DionysusTextBox
            typeof(DionysusTextBox), 
            //Redefine default behavior           
            new FrameworkPropertyMetadata(
                //Default value, can also omit this parameter
                null,
                //When IsReadOnly changed, this is executed 
                new PropertyChangedCallback(
                    (dpo, dpce) =>
                    {
                       //dpo hold the DionysusTextBox instance on which IsReachOnly changed
                       //dpce.NewValue hold the new value of IsReadOnly

                       //Run logic to set the background here, you are on the UI thread.

                       //Example of setting the BorderBrush from ARGB values:
                       var dioBox = dpo as DionysusTextBox;
                       //Should always be true, of course, it's just my OCD ;)
                       if (dioBox != null)                  
                       {
                          dioBox.BorderBrush = 
                              ColorConverter.ConvertFromString("#FFDDDDDD") as Color?;
                       }
                    })));

        //For the BorderBrush property
        BorderBrushProperty.OverrideMetadata(
            //On the type DionysusTextBox
            typeof(DionysusTextBox), 
            //Redefine default behavior           
            new FrameworkPropertyMetadata(
                //Default value
                ColorConverter.ConvertFromString("#FFDDDDDD") as Color?));
    }


    public DionysusTextBox()
    {
      SetStyle();
    }
}

请注意: UIPropertyMetadata != FrameworkPropertyMetadata

【讨论】:

  • 这对我有用,只有一个问题:我将 BackGroundProperty 设置为 Brushes.Gray 但我收到以下错误:'System.Drawing.SolidBrush' 不是属性的有效值'背景'..我应该将背景设置为什么?
  • @ChrisjanL 请改用System.Windows.Media.Brushes
  • 最后一个问题!如何在您的代码中完成以下 xaml:
  • @ChrisjanL 你会这样做:ColorConverter.ConvertFromString("#DDDDDD") as Color; 并将其分配给 BorderBrush。
  • 如何在静态构造函数中分配BorderBrush?