Как реализовать пользовательскую кисть в WPF?

где я могу узнать достаточно информации о том, как кисти работают для реализации моей собственной системы.Окна.Сми.Кисть? Я могу справиться со всем замораживаемым багажом, но не совсем очевидно, что мне нужно переопределить, чтобы заставить его работать.


Да, поэтому я не имел в виду, что хочу использовать предопределенную кисть. Я хочу расширить систему.Окна.Сми.Кисть, которая является абстрактным классом. Это все исключительно для моего собственного назидания. Я даже не знаю, какую щетку сделать. Я был просто пытаюсь понять, как работают кисти. Как в:

public AwesomeBrush : Brush
{

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

    ... // concrete brush stuff

}

4 ответов


вы не можете создать пользовательскую кисть WPF, унаследовав от System.Windows.Media.Brush class, потому что этот класс содержит абстрактные члены, которые являются внутренними.

если вы используете 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 и не имеет отношения к этот вопрос. Отдельное спасибо Микко Рантанен за его комментарий.


я быстро взглянул на существующие кисти, используя отражатель. Похоже, что их реализация довольно закрыта и зависит от множества internal сантехники. Хотя возможно реализовать собственную кисть, похоже, что это не поддерживаемый вариант. Возможно даже, что элементы управления WPF плотно привязаны к существующим щеткам и не будут работать с пользовательским.

скорее всего, лучший способ достичь чего-то похожего на пользовательские кисти-это используйте DrawingBrush С некоторой сложной логикой рисования. Вы можете составить рисунок кисти из сложных форм с помощью других кистей, так что это должно позволить вам достичь требуемой цели.

обновление после редактирования

поскольку это для образования, вам лучше всего загрузить отражатель и использовать его, чтобы увидеть, как работают кисти. Они не предназначены для самореализации, и поскольку они полагаются на некоторые internal классов, к которым программисты не имеют обычно это будет довольно трудно сделать.

хотя интересно то, что щетка документации есть замечание для наследников, чтобы направлять правильный способ наследования от кисти.


чтобы ответить на вопрос, почему вы можете захотеть иметь пользовательскую кисть, рассмотрите сложную геометрию, и вы хотите заполнить ее градиентом, который соответствует форме, изменяя цвета радиально от центра фигуры (или любой произвольной начальной точки).

нет способа сделать это со статической заливкой (которая исключает почти все существующие кисти). За исключением репликации объекта снова и снова и вложения их (и разработки корпуса, чтобы все это выглядело правильно), заполняя каждый из них другим цветом, единственный практичный способ - иметь кисть, которая может смотреть на заполняемый объект.

Это на самом деле выполнимо в формах.

но не похоже, что есть какой-либо способ сделать это в WPF, что неудачно.

на самом деле, кисти WPF в то же время удивительно мощные и удивительно ограничены. Они явно разработаны для какой-то концептуальной модели, но я совсем не уверен, что это тот, который полезен за пределами некоторых довольно тривиальные визуальные эффекты, и, как обычно, это было сделано более сложным со странными (плохо документированными) параметрами, что делает выполнение очень простым, несколько сложным.


я попробовал все возможные углы для решения создания пользовательской кисти, от использования MarkupExtensions до возни с атрибутами TypeConverter, затем меня осенило: вы просто создаете класс-оболочку на основе DependencyObject, создаете DependencyProperty типа Brush, реализуете свою настройку, а затем привязываете к DependencyProperty кисти.

после этого поместите пользовательскую кисть в Resources

  <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"/>

I подумайте, что это лучше, чем решение 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         
}