2010-06-24 57 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; 
     } 
    } 

我想这样做的原因:我们有一个包含很多单元格的数据网格,每个单元格都显示文本。我们在单元上显示一些验证信息,我们通过使用带有textblock和网格中的某些路径hosten的模板来实现此目的。这增加了额外的元素到可视化树中,当我们必须重新绘制(加载,切换窗口或排序)时,视觉树中的元素越多,花费的时间就越长。当它只是一个文本块时,比用网格控制要快大约1/3 - 1/2。所以我们想在文本框的顶部绘制我们的验证内容。

回答

2

你的问题是:

  1. GetVisualChild()应除非指数== base.VisualChildrenCount返回base.GetVisualChild(指数)。
  2. 你忘了打电话给AddVisualChild()时DrawingExtra为真或DrawingVisual改变
  3. 你忘了打电话给RemoveVisualChild()时DrawingExtra为假或DrawingVisual改变

您可以通过设置固定#2,#3 DrawingExtra上的PropertyChangedCallback并将代码添加到DrawingVisual的setter中。

说明:它实际上是将视觉添加到树中的AddVisualChild()调用。发生的事情是,由于GetVisualChild()中的错误,您的视觉被“意外”发现并显示,但它没有正确链接到视觉树中,因此您会遇到许多问题。

更新

我编辑的代码,如上所述,它完美地工作。这里是变化:

... 
     { 
     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,所以我上面的解决方案是一个破解。 – 2010-06-24 07:58:47

+1

我刚刚尝试了您的代码,并提供了我所建议的更改,并且工作完美。然后,我为DrawExtra属性制作了一个动画,并获得了一个闪烁的蓝色小框。 – 2010-06-24 08:30:44

+0

完全神奇,非常感谢! – 2010-06-24 23:10:24