Description
-
.NET Core Version: .NET 6 Version: 6.0.6, Commit 7cca709db2
-
Windows version: Windows 10 Version 21H2 (OS Build 19044.1826)
-
Does the bug reproduce also in WPF for .NET Framework 4.8?: No
Problem description:
I have a class which inherits FrameworkElement and is used to display points on a Canvas. The points are created by using a combination of Geometry, GeometryDrawing, and DrawingVisual. Because the points need to be centered around their location, they are offset by half of their width and height. This means that the DrawingVisual can have coordinates that are negative relative to the FrameworkElement. This causes issues with the tooltip of the FrameworkElement, which will not stay open when hovering over points with negative positions. It displays once and then disappears immediately.
The issue was not present for .NET Framework, and only appears when targeting .NET6.
This also happened for points with positive offsets, but could be prevented by implementing the MeasureOverride method to return the size of the FrameworkElement's visual elements. However there is no way to say that the FrameworkElement has visual elements outside its bounds, and the issue can not be mitigated for points with negative coordinates.
For .NET Framework, the MeasureOverride method does not need to be implemented and points with negative positions display the tooltip correctly.
Actual behavior:
The tooltip disappears immediately while hovering over any visual element with negative coordinates relative to the FrameworkElement.
Expected behavior:
The tooltip displays correctly while hovering over any visual element belonging to the FrameworkElement.
Minimal repro:
Below is the code for the inherited FrameworkElement class. I have also attached an example project showing the observed behavior.
FrameworkTestApp.zip
using System;
using System.Windows;
using System.Windows.Media;
namespace TestFrameworkElement
{
public class GeometryFrameworkElement : FrameworkElement
{
protected VisualCollection Children { get; set; }
protected override int VisualChildrenCount => Children.Count;
protected override Visual GetVisualChild(int index)
{
if (index < 0 || index >= Children.Count)
{
throw new ArgumentOutOfRangeException(nameof(index));
}
return Children[index];
}
protected override Size MeasureOverride(Size availableSize)
{
var left = 0d;
var right = 0d;
var top = 0d;
var bottom = 0d;
foreach (DrawingVisual visual in Children)
{
left = Math.Min(left, visual.ContentBounds.Left);
right = Math.Max(right, visual.ContentBounds.Right);
top = Math.Min(top, visual.ContentBounds.Top);
bottom = Math.Max(bottom, visual.ContentBounds.Bottom);
}
double width = right - left;
double height = bottom - top;
return new Size(width, height);
}
public GeometryFrameworkElement()
{
Children = new VisualCollection(this)
{
// Locations with positive coordinates display tooltip correctly
GetGeometryVisual(new Point(20, 20), new Size(10, 10), new Pen(Brushes.ForestGreen, 1)),
GetGeometryVisual(new Point(0, 0), new Size(10, 10), new Pen(Brushes.ForestGreen, 1)),
// Locations with negative coordinates do not
GetGeometryVisual(new Point(-20, -20), new Size(10, 10), new Pen(Brushes.OrangeRed, 1)),
// Centered, only works for bottom right quadrant
GetGeometryVisual(new Point(-5, -5), new Size(10, 10), new Pen(Brushes.Yellow, 1)),
};
ToolTip = "Framework element tooltip";
}
private DrawingVisual GetGeometryVisual(Point location, Size size, Pen pen)
{
var geometry = new RectangleGeometry(new Rect(location, size));
geometry.Freeze();
var gd = new GeometryDrawing(pen.Brush, pen, geometry);
gd.Freeze();
var drawingVisual = new DrawingVisual();
DrawingContext dc = drawingVisual.RenderOpen();
dc.DrawDrawing(gd);
dc.Close();
return drawingVisual;
}
}
}