2010-06-24 6 views
1

Я хочу, чтобы иметь возможность рисовать на вершине TextBlock, и нашел способ сделать это, но я не могу удалить чертеж, как только он есть. Вот код.WPF: рисование поверх TextBlock

public class DerivedTextBlock : TextBlock { 

     public Boolean DrawExtra { 
     get { return (Boolean)GetValue(DrawExtraProperty); } 
     set { SetValue(DrawExtraProperty, value); } 
     } 

     // Using a DependencyProperty as the backing store for DrawExtra. This enables animation, styling, binding, etc... 
     public static readonly DependencyProperty DrawExtraProperty = 
      DependencyProperty.Register("DrawExtra", typeof(Boolean), typeof(DerivedTextBlock), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.AffectsArrange)); 

     public DrawingVisual DrawingVisual { get; set; } 

     public DerivedTextBlock() { 
     DrawingVisual = this.CreateDrawingVisualRectangle(); 
     } 

     protected override int VisualChildrenCount { 
     get { 
      //if we want to draw our extra info, add one to 
      // our visualChildrenCount, usually with a textblock it is 0 
      if (DrawExtra) { 
       return base.VisualChildrenCount + 1; 
      } 
      else { 
       return base.VisualChildrenCount; 
      } 
     } 
     } 

     protected override Visual GetVisualChild(int index) { 
     return DrawingVisual; 
     } 

     // Create a DrawingVisual that contains a rectangle. 
     private DrawingVisual CreateDrawingVisualRectangle() { 
     DrawingVisual drawingVisual = new DrawingVisual(); 

     // Retrieve the DrawingContext in order to create new drawing content. 
     DrawingContext drawingContext = drawingVisual.RenderOpen(); 

     // Create a rectangle and draw it in the DrawingContext. 
     Rect rect = new Rect(new Point(10.0, 0), new Size(10.0/2.0, 10)); 
     drawingContext.DrawRectangle(Brushes.LightBlue, (Pen)null, rect); 

     // Persist the drawing content. 
     drawingContext.Close(); 

     return drawingVisual; 
     } 
    } 

Причина Я хочу сделать это: у нас есть набор данных с большим количеством ячеек, каждая ячейка отображает текст. мы показываем некоторую информацию о проверке на ячейках, и мы делаем это, используя шаблон с текстовым блоком и некоторыми хостами-хостами в сетке. накладные расходы на это добавляют дополнительные элементы к визуальному дереву, и когда нам приходится перерисовывать (при загрузке, переключении окон или в сортировке), требуется намного больше элементов в визуальном дереве. когда это всего лишь текстовый блок, он примерно на 1/3 - 1/2 быстрее, чем управление с сеткой. Поэтому мы хотели бы нарисовать наш материал для проверки прямо поверх текстового поля.

ответ

2

Ваши проблемы:

  1. GetVisualChild() должен возвращать base.GetVisualChild (индекс) за исключением случаев индекса == base.VisualChildrenCount.
  2. Вы забыли назвать AddVisualChild(), когда DrawingExtra становится истинным или DrawingVisual изменения
  3. Вы забыли назвать RemoveVisualChild(), когда DrawingExtra становится ложной или DrawingVisual изменения

Вы можете исправить # 2 и # 3, установив свойство PropertyChangedCallback на DrawingExtra и добавление кода в установщик DrawingVisual.

Объяснение: Это вызов AddVisualChild(), который на самом деле добавляет визуал в дерево. Что происходит, так это то, что ваш визуал обнаруживается и отображается «случайно» из-за вашей ошибки в GetVisualChild(), но он неправильно связан с визуальным деревом, так что у вас будет много проблем.

Update

Я редактировал свой код, как описано выше, и она работала отлично. Ниже приведены изменения:

... 
     { 
     PropertyChangedCallback = (obj, e) => 
      { 
      var textBlock = (DerivedTextBlock)obj; 
      if((bool)e.OldValue) textBlock.RemoveVisualChild(textBlock.DrawingVisual); 
      if((bool)e.NewValue) textBlock.AddVisualChild(textBlock.DrawingVisual); 
      } 
     }); 

    public DrawingVisual DrawingVisual 
    { 
    get { return _drawingVisual; } 
    set 
    { 
     if(DrawExtra) RemoveVisualChild(_drawingVisual); 
     _drawingVisual = value; 
     if(DrawExtra) AddVisualChild(_drawingVisual); 
    } 
    } 
    private DrawingVisual _drawingVisual; 

... 

    protected override int VisualChildrenCount 
    { 
    get { return base.VisualChildrenCount + (DrawExtra ? 1 : 0); } 
    } 

    protected override Visual GetVisualChild(int index) 
    { 
    return index==base.VisualChildrenCount ? DrawingVisual : base.GetVisualChild(index); 
    } 
+0

Я попробовал AddVisualChild(), и кажется, что он игнорируется для TextBlock, поэтому мое решение выше - это взломать. –

+1

Я просто попробовал свой код с изменениями, которые я предложил, и он отлично работал. Затем я анимировал свойство DrawExtra и получил небольшую мигающую синюю коробку. –

+0

полностью волшебство, спасибо! –