代码之家  ›  专栏  ›  技术社区  ›  Aran Mulholland JohnnyAce

WPF:在文本块顶部绘制

  •  1
  • Aran Mulholland JohnnyAce  · 技术社区  · 14 年前

    我希望能够绘制到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时,它比使用网格控件快大约1/3-1/2。所以我们想在文本框的顶部绘制验证内容。

    1 回复  |  直到 14 年前
        1
  •  2
  •   Ray Burns    14 年前

    你的问题是:

    1. GetVisualChild()应返回base.GetVisualChild(index),除非index==base.VisualChildrenCount。
    2. 当DrawingExtra变为false或DrawingVisualChanges时,您忘记调用RemoveVisualChild()

    通过在DrawingExtra上设置PropertyChangedCallback并向DrawingVisual的setter添加代码,可以修复#2和#3。

    更新

    我按照上面的描述编辑了你的代码,它运行得非常好。以下是更改:

    ...
          {
            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);
      }