2

我正在使用 Adorner 在 WPF DataGrid 的选定单元格中放置一个指示器三角形(与在 Excel 中的单元格中插入注释时获得的效果相同)。不幸的是,我让随机的装饰者出现在他们不应该出现的地方。

假设有 3 个单元格应该有装饰器;我得到了 3 个额外的单元格,它们也有装饰器。我已经证明只有 3 个在代码中被创建,即使有 6 个出现。我在 ElementGenerated 事件中创建/删除装饰器。

额外的实例始终位于网格的可视区域中尚未出现的单元格上,因此我相当确定问题是由于网格列的虚拟化以及网格正在重用单元格而不是创建新的单元格和因此 ElementGenerated 事件不会再次触发,并且 Adorner 不会在不需要的地方被移除。

当 Cell 被重新使用时,我找不到可以使用的事件。任何建议将不胜感激。

这是三角形装饰器的代码:-

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

1 回答 1

0

当行被虚拟化重用时,您可以使用DataGrid.LoadingRow和事件来获得通知。DataGrid.UnloadingRow不幸的是,我认为你不能从那里进入牢房。

您可以尝试附加到DataGridCell.LoadedDataGridCell.DataContextChanged事件以创建和更新您的装饰器。

于 2015-01-06T14:13:09.643 回答