-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Description
Description
Potentially related topics:
Why the Visual.VisualOffset is double type but run the compositor in floats? #5389
Q: Can we replace the MIL code withdouble
? Or provide an enum type to control whether calculations usefloat
ordouble
?
I am developing timeline-related controls. If zoomed into frame mode view with each frame scale set to 500px, a 1-hour segment would span a width of 500px * 24fps * 3600s = 43,200,000 (≈2^25, 43 million)
. The element does not render correctly, appearing to lose precision and exhibit ghosting.
large_view_render_error.mp4
large_view_render_error_scroll.mp4
Reproduction Steps
mini demo: https://github.com/CodingOctocat/LargeViewRenderError
<Window x:Class="LargeViewRenderError.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:LargeViewRenderError"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="800"
Height="450"
Loaded="Window_Loaded"
SnapsToDevicePixels="True"
UseLayoutRounding="True"
mc:Ignorable="d">
<!-- 所有元素的 SnapsToDevicePixels 和 UseLayoutRounding 都进行过排列组合测试。 -->
<ScrollViewer x:Name="sv"
HorizontalScrollBarVisibility="Visible"
SnapsToDevicePixels="True"
UseLayoutRounding="True"
VerticalScrollBarVisibility="Visible">
<Canvas x:Name="canvas"
Width="1000000000"
Height="800"
Background="Wheat"
MouseDown="Canvas_MouseDown"
MouseMove="Canvas_MouseMove"
MouseUp="Canvas_MouseUp"
SnapsToDevicePixels="True"
UseLayoutRounding="True" />
</ScrollViewer>
</Window>
public partial class MainWindow : Window
{
private AdornerLayer _adornerLayer = null!;
private bool _isSelecting;
private SelectionBoxAdorner? _selectionBoxAdorner;
private Point _startPoint;
public MainWindow()
{
InitializeComponent();
}
// 鼠标按下事件,开始选区
private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
{
// 只有左键点击时才开始
if (e.ButtonState == MouseButtonState.Pressed && e.ChangedButton == MouseButton.Left)
{
_startPoint = e.GetPosition(canvas);
_isSelecting = true;
// 创建 SelectionBoxAdorner 并添加到 AdornerLayer
_selectionBoxAdorner = new SelectionBoxAdorner(canvas, _startPoint);
_adornerLayer.Add(_selectionBoxAdorner);
}
}
// 鼠标移动事件,更新选区大小
private void Canvas_MouseMove(object sender, MouseEventArgs e)
{
if (_isSelecting && _selectionBoxAdorner != null)
{
var currentPoint = e.GetPosition(canvas);
_selectionBoxAdorner.UpdateEndPoint(currentPoint);
Debug.WriteLine(">>> " + currentPoint);
}
}
// 鼠标松开事件,结束选区
private void Canvas_MouseUp(object sender, MouseButtonEventArgs e)
{
if (_isSelecting)
{
_isSelecting = false;
if (_selectionBoxAdorner != null)
{
_adornerLayer.Remove(_selectionBoxAdorner);
}
}
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
_adornerLayer = AdornerLayer.GetAdornerLayer(canvas); // 获取 AdornerLayer
}
}
public class SelectionBoxAdorner : Adorner
{
private readonly Pen _border;
private Point _end;
private Point _start;
public Brush BorderBrush { get; set; } = Brushes.DodgerBlue;
public Brush Fill { get; set; }
public SelectionBoxAdorner(UIElement adornedElement, Point start) : base(adornedElement)
{
BorderBrush = Brushes.DodgerBlue;
BorderBrush.Freeze();
Fill = new SolidColorBrush(Color.FromArgb(50, 0, 120, 215));
Fill.Freeze();
_border = new(BorderBrush, 1);
_start = start;
_end = start;
IsHitTestVisible = false;
// 测试
UseLayoutRounding = true;
SnapsToDevicePixels = true;
}
public Rect GetSelectionRect()
{
return new Rect(_start, _end);
}
public void UpdateEndPoint(Point end)
{
_end = end;
_end.X = Math.Max(_end.X, 0);
_end.Y = Math.Max(_end.Y, 0);
InvalidateVisual();
}
protected override void OnRender(DrawingContext dc)
{
var rect = GetSelectionRect();
dc.DrawRectangle(Fill, _border, rect);
}
}
Expected behavior
Correctly render elements larger than 2^21 pixels.
Actual behavior
Elements larger than 2^21px cannot be rendered correctly. Issues such as loss of precision, screen flickering, and ghosting may occur.
Test:
2^23: Rendering error

2^22: Rendering imperfect

2^21: Perfect rendering

Regression?
No response
Known Workarounds
Using IScrollInfo + UI virtualization.
Impact
No response
Configuration
- .NET9
- Win11 24h2
- x64
Other information
No response