Подтвердить что ты не робот

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

Где я могу узнать достаточно информации о том, как работают Brushes для реализации моей собственной System.Windows.Media.Brush? Я могу обрабатывать весь замороженный багаж, но это не совсем очевидно, что мне нужно переопределить, чтобы заставить его работать.


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

public AwesomeBrush : Brush
{

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

    ... // concrete brush stuff

}
4b9b3361

Ответ 1

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

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

Ответ 2

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

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

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

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

Хотя интересно, что Brush documentation имеет замечание для наследователей, чтобы правильно наследовать от Brush.

Дополнительные обновления

Когда я ковырялся, я нашел довольно аккуратный способ добиться чего-то подобного на

Ответ 3

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

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

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

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

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

Ответ 4

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

Затем добавьте пользовательскую кисть в раздел Ресурсы

  <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         
}