dotnet / dotnet/wpf

Unable to render oversized UI element correctly

Open
#11,161 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
C#
Stars
7.7k
Forks
1.3k
Avg merge
1d 11h
Merged PRs (30d)
61

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 with `double`? Or provide an enum type to control whether calculations use `float` or `double`?

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.

https://github.com/user-attachments/assets/7b46c586-e995-40ce-833d-2430f4289fea

https://github.com/user-attachments/assets/2cb307fa-af62-44be-8d5f-e95bdd3e0f04

### Reproduction Steps

mini demo: https://github.com/CodingOctocat/LargeViewRenderError

```xaml




```

```cs
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
}
}
```

```cs
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
23

## 2^22: Rendering imperfect
22

## 2^21: Perfect rendering
21

### Regression?

_No response_

### Known Workarounds

Using IScrollInfo + UI virtualization.

### Impact

_No response_

### Configuration

- .NET9
- Win11 24h2
- x64

### Other information

_No response_

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.