Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I implement a custom Brush in WPF?

Tags:

.net

wpf

brush

Where can I find out enough info about how Brushes work to implement my own System.Windows.Media.Brush? I can handle all of the freezable baggage, but it's not really obvious what I need to override to get it to work.


Yeah, so I didn't mean that I want to use a predefined brush. I want to extend System.Windows.Media.Brush, which is an abstract class. This is all purely for my own edification. I'm not even sure what kind of brush I could make. I was just trying to learn how brushes work. As in:

public AwesomeBrush : Brush
{

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

    ... // concrete brush stuff

}
like image 972
MojoFilter Avatar asked Apr 27 '09 17:04

MojoFilter


People also ask

What is WPF brush?

The following list describes the different types of WPF brushes: SolidColorBrush: Paints an area with a solid Color. LinearGradientBrush: Paints an area with a linear gradient. RadialGradientBrush: Paints an area with a radial gradient. ImageBrush: Paints an area with an image (represented by an ImageSource object).

What is brush in XAML?

Use Brush objects to paint the interiors and outlines of XAML shapes, text, and controls, making them visible in your application UI.


3 Answers

I had a quick look at the existing brushes using the Reflector. It seems like their implementation is pretty closed up and depends on lots of internal plumbing. While it might be possible to implement your own brush it seems like it is not a supported option. It could even be that the WPF controls are tied tightly to the existing brushes and will not work with a custom one.

Most likely the best way to achieve something resembling custom brushes is to use the DrawingBrush with some complex drawing logic. You can compose drawing brush from complex shapes using other brushes so this should let you achieve the required goal.

Update after edit

As this is for education, you might be best off downloading the Reflector and using that to see how the brushes work. They are not meant to be self-implemented and since they rely on some internal classes to which programmers do not have access normally it will be quite hard to do so.

Though what makes it interesting is that the Brush documentation does have a remark for inheritors to guide in the correct way to inherit from the Brush.

More updates

When poking around I found a quite neat way to achieve something similar on a chinese blog. The trick there is to use a markup extension so it just looks like a brush. In reality it creates a new image brush based on its attributes. Seems he came to the same conclusion that there are some internal classes which prevent the easy implementation.

like image 169
Mikko Rantanen Avatar answered Oct 16 '22 22:10

Mikko Rantanen


To answer the question of why you might want to have a custom brush, consider a complex geometry and you want to fill it with a gradient that matches the shape while changing colours radially from the center of the shape (or any arbitrary starting point).

There is no way to do this with a static fill (which eliminates pretty much all the existing brushes). Short of replicating the object over and over and nesting them (and working out the hulling to make it all look right), filling each one with a different colour, the only practical way is to have a brush that can look at the object being filled.

This is actually doable in Forms.

But it doesn't look like there's any way to do it in WPF, which is unfortunate.

In fact, WPF's brushes are at the same time surprisingly powerful AND surprisingly limited. They're clearly designed to some concept model, but I'm not at all sure it's one that's useful beyond some pretty trivial visual effects, and as usual, it's been made more complex with strange (poorly documented) parameters that makes doing the very simple, somewhat complicated.

like image 42
Jeff Lewis Avatar answered Oct 16 '22 21:10

Jeff Lewis


I tried every possible angle for a solution to making a custom brush, from using MarkupExtensions to messing around with TypeConverter attributes, then it dawwned on me: you simply create a wrapper class based on DependencyObject, create a DependencyProperty of type Brush, implement your customization then Bind to the Brush DependencyProperty.

Afterwards, put the custom brush in Resources

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

Then Bind to it:

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

I think this is better than the MarkupExtension solution because you can't put one in Resources and therefore you have to redefine the custom settings every time you use it.

In any case, this would seem to be a simple solution to inheriting from any Wpf object, and with the flexibility of Bindings you can also bind to members of the wrapped Wpf object itself.

Here's the simple class:

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         
}
like image 4
countzero1984 Avatar answered Oct 16 '22 21:10

countzero1984