WPF DataGrid和Adorners

时间:2015-01-06 11:31:36

标签: wpf datagrid adorner adornerlayer adornerdecorator

我正在使用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 :(得分:0)

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

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