title: WPF DataGrid and Adorners
body: <p>I am using an Adorner to place an indicator triangle in selected cells of a WPF DataGrid (the same effect as you get when inserting a comment in a cell in Excel). Unfortunately I am getting random Adorners appearing where they shouldn't.</p>
  
  <p>Supposing there are 3 cells that should have the Adorner; I am getting 3 extra cells that also have the Adorner. I have proved that only 3 are being created in code even though there are 6 appearing. I create/remove the Adorners in the ElementGenerated event.</p>
  
  <p>The extra instances are always on cells that are not yet in the visual area of the grid and so I am fairly certain that the problem is due to virtualization of the grid columns and that the grid is re-using cells rather than creating new ones and as such the ElementGenerated event does not fire again and the Adorner is not removed where it is not needed.</p>
  
  <p>I can't find an event that I could use when the Cell is re-used. Any suggestions would be gratefully received.</p>
  
  <p>This is the code for the triangle Adorner:-</p>
  
  <pre><code>public class TriangleAdorner : Adorner
  {
      private readonly double _offsetX;
      private readonly double _offsetY;
  
      public TriangleAdorner(UIElement adornedElement)
          : this(adornedElement, 0, 0)
      {
      }
  
      public TriangleAdorner(UIElement adornedElement, double offsetX, double offsetY)
          : base(adornedElement)
      {
          _offsetX = offsetX;
          _offsetY = offsetY;
      }
  
      protected override void OnRender(DrawingContext drawingContext)
      {
          //Rect adornedElementRect = new Rect(this.AdornedElement.DesiredSize);
  
          // all examples seem to use the above but this didn't get the adorner in the correct place for me
          Rect adornedElementRect = new Rect(this.AdornedElement.RenderSize);
  
          PointCollection myPointCollection = new PointCollection
                                                  {
                                                      new Point(adornedElementRect.TopLeft.X + 6 + _offsetX, adornedElementRect.TopLeft.Y + 1 + _offsetY), 
                                                      new Point(adornedElementRect.TopLeft.X + 1 + _offsetX, adornedElementRect.TopLeft.Y + 1 + _offsetY), 
                                                      new Point(adornedElementRect.TopLeft.X + 1 + _offsetX, adornedElementRect.TopLeft.Y + 6 + _offsetY)
                                                  };
  
          StreamGeometry streamGeometry = new StreamGeometry();
          using (StreamGeometryContext geometryContext = streamGeometry.Open())
          {
              geometryContext.BeginFigure(myPointCollection[0], true, true);
              PointCollection points = new PointCollection
                                           {
                                               myPointCollection[1],
                                               myPointCollection[2]
                                           };
              geometryContext.PolyLineTo(points, true, true);
          }
  
          drawingContext.DrawGeometry(Brushes.Red, new Pen(Brushes.Red, 0), streamGeometry);
  
      }
  
      protected override Size MeasureOverride(Size constraint)
      {
          var result = base.MeasureOverride(constraint);
  
          InvalidateVisual();
          return result;
      }
  </code></pre>
  
  <p>And the event that adds/removes:-</p>
  
  <pre><code>private void DataGrid_ElementGenerated(object sender, ElementGeneratedEventArgs e)
  {
          FrameworkElement element = (FrameworkElement) e.DataGridCell;
          if (element == null) return;
  
          AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(element);
          if (adornerLayer != null)
          {
  
              if (CellAdornerRequired())
              {
                  Adorner[] children = adornerLayer.GetAdorners(element);
                  if (children == null || !children.Any())
                  {
                      adornerLayer.Add(new TriangleAdorner(element));
                  }
              }
              else
              {
                  Adorner[] children = adornerLayer.GetAdorners(element);
                  if (children != null &amp;&amp; children.Any())
                  {
                      foreach (var adorner in children)
                      {
                          adornerLayer.Remove(adorner);
                      }
                  }
              }
          }
      }
  </code></pre>