代码之家  ›  专栏  ›  技术社区  ›  MojoFilter

如何在WPF中实现自定义画笔?

  •  13
  • MojoFilter  · 技术社区  · 16 年前

    在哪里可以找到足够的关于画笔如何工作以实现自己的system.windows.media.brush的信息?我可以处理所有可免费的行李,但我不太清楚需要覆盖什么才能使它工作。


    是的,所以我不是说我想使用一个预定义的画笔。我想扩展System.Windows.Media.Brush,这是一个抽象类。这完全是为了我自己的启迪。我甚至不知道我能做什么样的刷子。我只是想学习刷子的工作原理。如:

    public AwesomeBrush : Brush
    {
    
        protected override Freezable CreateInstanceCore()
        {
            return new AwesomeBrush();
        }
    
        ... // concrete brush stuff
    
    }
    
    4 回复  |  直到 9 年前
        1
  •  3
  •   M. Jahedbozorgan    9 年前

    无法通过继承来自的自定义WPF画笔 System.Windows.Media.Brush 类,因为该类包含内部的抽象成员。

    如果使用Reflector查看 系统.windows.media.brush 类,您将看到以下内部抽象方法:

    internal abstract DUCE.ResourceHandle AddRefOnChannelCore(DUCE.Channel channel);
    internal abstract DUCE.Channel GetChannelCore(int index);
    internal abstract int GetChannelCountCore();
    internal abstract DUCE.ResourceHandle GetHandleCore(DUCE.Channel channel);
    internal abstract void ReleaseOnChannelCore(DUCE.Channel channel);
    

    这些必须重写,但不能重写,因为它们是内部的。

    注: 编辑了我的答案,因为以前的答案是关于 System.Drawing.Brush 与这个问题无关。特别感谢Mikko Rantanen的评论。

        2
  •  9
  •   Mikko Rantanen    16 年前

    我用 Reflector . 它们的实现似乎非常封闭,并且依赖于 internal 管道工程。虽然可能实现自己的画笔,但它似乎不是受支持的选项。甚至可能是WPF控件与现有的画笔紧密相连,无法与自定义的画笔一起使用。

    实现类似自定义画笔的最佳方法很可能是使用 DrawingBrush 有一些复杂的绘图逻辑。您可以使用其他画笔从复杂形状组成绘图画笔,这样可以实现所需的目标。

    编辑后更新

    因为这是为了教育,你最好下载反射镜,然后用它来看看刷子是如何工作的。它们并不意味着自我实现,因为它们依赖于 内部的 程序员通常无法访问的类将很难做到这一点。

    但有趣的是 Brush documentation 确实有一句话让继承者以正确的方式从画笔继承。

    更多更新

    当我四处摸索时,我发现了一种非常巧妙的方法,可以在 chinese blog . 这里的技巧是使用标记扩展,使它看起来像刷子。实际上,它基于自己的属性创建了一个新的图像画笔。似乎他也得出了同样的结论,即有一些内部类阻止了简单的实现。

        3
  •  5
  •   Jeff Lewis    13 年前

    要回答为什么要使用自定义画笔的问题,请考虑复杂的几何图形,并使用与形状匹配的渐变填充它,同时从形状的中心(或任意起点)径向更改颜色。

    使用静态填充无法做到这一点(这会消除几乎所有现有的画笔)。除了一遍又一遍地复制对象并将其嵌套(并计算出外壳以使其看起来正确),用不同的颜色填充每个对象之外,唯一实用的方法是使用一个可以查看被填充对象的画笔。

    这实际上在形式上是可行的。

    但看起来在WPF中没有任何方法可以做到这一点,这是不幸的。

    事实上,WPF的刷子同时具有惊人的强大和有限性。它们显然是根据一些概念模型设计的,但我一点也不确定它是否比一些非常微不足道的视觉效果更有用,而且像往常一样,它是由奇怪的(文档记录不好的)参数变得更复杂,这使得做起来非常简单,有点复杂。

        4
  •  3
  •   countzero1984    15 年前

    我尝试了每一个可能的角度来解决制作自定义画笔的问题,从使用MarkupExtensions到处理TypeConverter属性,然后我明白了:您只需基于DependencyObject创建一个包装类,创建一个类型为Brush的DependencyProperty,实现您的自定义,然后绑定到Brush DependencyProperty。

    然后,将自定义画笔放到资源中

      <l:CustomBrush x:Key="CustomBrush" Brush="Magenta" />
    

    然后绑定到它:

      <Line X1="0" Y1="-5" X2="200" Y2="-5" 
            Stroke="{Binding Source={StaticResource CustomBrush}, Path=Brush}" 
            StrokeThickness="12"/>
    

    我认为这比MarkupExtension解决方案更好,因为您不能将它放入资源中,因此每次使用它时都必须重新定义自定义设置。

    在任何情况下,这似乎是从任何WPF对象继承的一个简单的解决方案,并且由于绑定的灵活性,您还可以绑定到被包装的WPF对象本身的成员。

    下面是简单的类:

    public class CustomBrush : DependencyObject
    {
       public CustomBrush()
       {
          this.Brush = Brushes.Azure;      
       }
    
       #region Brush DependencyProperty
    
       [BindableAttribute(true)]
       public Brush Brush
       {
         get { return (Brush)GetValue(BrushProperty); }
         set { SetValue(BrushProperty, value); }
       }
       public static readonly DependencyProperty BrushProperty =
          DependencyProperty.Register(
             "Brush",
             typeof(Brush),
             typeof(CustomBrush),
             new UIPropertyMetadata(null));
    
       #endregion         
    }