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

时间:2009-04-27 17:38:23

标签: .net wpf brush

我在哪里可以找到有关Brushes如何实现我自己的System.Windows.Media.Brush的足够信息?我可以处理所有可冻结的行李,但是为了让它起作用我需要覆盖的并不是很明显。


是的,所以我并不是说我想使用预定义的画笔。我想扩展System.Windows.Media.Brush,这是一个抽象类。这完全是为了我自己的启发。我甚至不确定我能用什么样的刷子。我只是想了解刷子是如何工作的。如:

public AwesomeBrush : Brush
{

    protected override Freezable CreateInstanceCore()
    {
        return new AwesomeBrush();
    }

    ... // concrete brush stuff

}

4 个答案:

答案 0 :(得分:9)

我使用Reflector快速查看了现有的画笔。看起来他们的实现非常封闭,取决于很多internal管道。虽然可能有可能实现自己的画笔,但似乎它不是受支持的选项。甚至可能是WPF控件与现有画笔紧密相关,并且不适用于自定义画笔。

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

修改后更新

由于这是针对教育的,您可能最好下载Reflector并使用它来查看画笔的工作原理。它们并不意味着是自我实现的,因为它们依赖于程序员通常无法访问的某些internal类,所以很难这样做。

虽然令人感兴趣的是Brush documentation确实有继承者的注释,以正确的方式从Brush继承。

更多更新

当我四处寻找时,我找到了一种非常简洁的方法来在chinese blog上实现类似的东西。诀窍是使用标记扩展,所以它看起来像一个刷子。实际上,它会根据其属性创建一个新的图像画笔。似乎他得出了相同的结论,即有一些内部类阻止了简单的实现。

答案 1 :(得分:5)

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

使用静态填充(几乎消除了所有现有的画笔)无法做到这一点。如果不能一遍又一遍地复制对象并将它们嵌套(并进行脱壳以使其全部看起来正确),用不同的颜色填充每一个,唯一可行的方法是使用可以查看被填充物体的刷子

这在Forms中实际上是可行的。

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

事实上,WPF的画笔同时具有惊人的强大功能,令人惊讶地受到限制。它们显然是针对某些概念模型设计的,但我完全不确定它是否超出了一些非常微不足道的视觉效果,并且像往常一样,它被制作得更加复杂,奇怪的(记录不完整的)参数使得它非常简单,有点复杂。

答案 2 :(得分:3)

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

如果使用Reflector查看System.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的评论。

答案 3 :(得分:3)

我尝试了每个可能的角度来制作自定义画笔的解决方案,从使用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对象继承的简单解决方案,并且通过Bindings的灵活性,您还可以绑定到包装的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         
}