【问题标题】:WPF DataGrid and AdornersWPF DataGrid 和装饰器
【发布时间】:2015-03-04 01:34:27
【问题描述】:

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

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

额外的实例始终位于网格可视区域中尚未出现的单元格上,因此我相当确定问题是由于网格列的虚拟化以及网格正在重用单元格而不是创建新的,因此 ElementGenerated 事件不会再次触发,并且 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);
                    }
                }
            }
        }
    }

【问题讨论】:

    标签: wpf datagrid adorner adornerlayer adornerdecorator


    【解决方案1】:

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

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

    【讨论】:

    • 额外的装饰器出现在查看区域之外的列中。 DataGrid 不会在这些列中加载单元格,直到需要它们。我没有提到 Grid 是 WPF DataGrid 的自定义版本,并且有一个自定义模板列。我在 TriangleAdorner 类中创建了一个 Guid,以便我可以在 OnRender 事件中识别装饰器。似乎以某种方式在不止一个地方显示了相同的装饰器实例。感谢您的回复。
    猜你喜欢
    • 2016-11-24
    • 2013-02-06
    • 2010-11-25
    • 2010-11-24
    • 1970-01-01
    • 1970-01-01
    • 2011-03-14
    • 2010-10-04
    • 1970-01-01
    相关资源
    最近更新 更多