首页 文章

WPF DataGrid和Adorners

提问于
浏览
1

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

假设有3个细胞应该有Adorner;我有3个额外的细胞,也有Adorner . 我已经证明,即使有6个出现,代码中也只创建了3个 . 我在ElementGenerated事件中创建/删除Adorners .

额外的实例总是位于尚未位于网格可视区域的单元格上,所以我很确定问题是由于网格列的虚拟化以及网格重新使用单元格而不是创建新单元格而因此,ElementGenerated事件不会再次触发,并且不会在不需要的地方删除Adorner .

重新使用Cell时,我找不到可以使用的事件 . 我们将非常感激地收到任何建议 .

这是三角形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 回答

  • 0

    您可以使用 DataGrid.LoadingRowDataGrid.UnloadingRow 事件在虚拟化重用行时收到通知 . 不幸的是,我认为你不能从那里进入细胞 .

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

相关问题