WPF DataGrid и Adorners

Я использую Adorner для размещения треугольника индикатора в выбранных ячейках таблицы данных WPF (тот же эффект, который вы получаете при вставке комментария в ячейку в Excel). К сожалению, я получаю случайные украшения, появляющиеся там, где они не должны.

Предположим, есть 3 клетки, которые должны иметь Adorner; Я получаю 3 дополнительные клетки, которые также имеют Adorner. Я доказал, что только 3 создаются в коде, хотя появляются 6. Я создаю / удаляю Adorners в событии ElementGenerated.

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

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

Это код для треугольника Adorner:-

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

И событие, которое добавляет / удаляет: -

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 && children.Any())
                {
                    foreach (var adorner in children)
                    {
                        adornerLayer.Remove(adorner);
                    }
                }
            }
        }
    }

1 ответ

Вы можете использовать DataGrid.LoadingRow а также DataGrid.UnloadingRow события, чтобы получить уведомление, когда строка повторно используется виртуализацией. К сожалению, я не думаю, что вы можете добраться до камер оттуда.

Вы можете попытаться прикрепить к DataGridCell.Loaded а также DataGridCell.DataContextChanged события для создания и обновления ваших украшателей.

Другие вопросы по тегам