WPF 是滚动查看器的水平偏移量,在较大值下准确

本文关键字:偏移量 滚动 水平 WPF | 更新日期: 2023-09-27 18:34:35

我决定用完整的代码来解决这个问题。我创建了一个测试用例,只是演示了我认为的奇怪行为,以便其他人可以运行代码。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Media;
namespace Test
{
  public class TestSizeVisual: FrameworkElement
  {
    public double MinimumXInDIPs
    {
      get { return (double)GetValue(MinimumXInDIPsProperty); }
      set
      {
        SetValue(MinimumXInDIPsProperty, value);
      }
    }
    public static readonly DependencyProperty MinimumXInDIPsProperty =
      DependencyProperty.Register("MinimumXInDIPs",
      typeof(double), typeof(TestSizeVisual),
      new FrameworkPropertyMetadata(new double(), new PropertyChangedCallback(Redraw)));
    public double ViewportWidth
    {
      get { return (double)GetValue(ViewportWidthProperty); }
      set
      {
        SetValue(ViewportWidthProperty, value);
      }
    }
    public static readonly DependencyProperty ViewportWidthProperty =
      DependencyProperty.Register("ViewportWidth",
      typeof(double), typeof(TestSizeVisual),
      new FrameworkPropertyMetadata(new double(), FrameworkPropertyMetadataOptions.AffectsMeasure));

    VisualCollection visuals;
    protected override Size MeasureOverride(Size availableSize)
    {
      return new Size(50000000000, 50);
    }
    public TestSizeVisual()
    {
      visuals = new VisualCollection(this);
      this.Loaded += new RoutedEventHandler(TestSizeVisual_Loaded);
    }
    void TestSizeVisual_Loaded(object sender, RoutedEventArgs e)
    {
      DrawSignal();
    }
    private static void Redraw(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
      TestSizeVisual sg = d as TestSizeVisual;
      if (sg != null && sg.IsLoaded)
      {
        sg.DrawSignal();
      }
    }

    private void DrawSignal()
    {
      DrawingVisual signalbox = new DrawingVisual();
      using (DrawingContext dc = signalbox.RenderOpen())
      {
        dc.DrawRectangle(Brushes.Orange, new Pen(Brushes.Black, 2), new Rect(new Point(0, 0), new Point(1000000000, ActualHeight)));
        dc.DrawRectangle(Brushes.Purple, new Pen(Brushes.Black, 2), new Rect(new Point(MinimumXInDIPs, 2), new Point(MinimumXInDIPs + 10, 6)));
        dc.DrawRectangle(Brushes.Purple, new Pen(Brushes.Black, 2), new Rect(new Point(MinimumXInDIPs + ViewportWidth - 10, 2), new Point(MinimumXInDIPs + ViewportWidth, 6)));
        dc.DrawLine(new Pen(Brushes.Black, 2), new Point(MinimumXInDIPs, 10),
                      new Point(MinimumXInDIPs + ViewportWidth, 10));
      }
      visuals.Add(signalbox);
      InvalidateVisual();

    }

    protected override Visual GetVisualChild(int index)
    {
      return visuals[index];
    }
    protected override int VisualChildrenCount
    {
      get
      {
        return visuals.Count;
      }
    }
  }
}

xaml 文件如下所示:

<ScrollViewer 
    x:Name="scrollviewer1"
    HorizontalAlignment="Stretch"    
    VerticalAlignment="Stretch"
    HorizontalContentAlignment="Left"
    HorizontalScrollBarVisibility="Visible"
    VerticalScrollBarVisibility="Visible"
    >
    <test:TestSizeVisual 
      MinimumXInDIPs="{Binding ElementName=scrollviewer1, Path=HorizontalOffset}"
      ViewportWidth="{Binding ElementName=scrollviewer1, Path=ViewportWidth}"
      />
  </ScrollViewer>

当您滚动显示较小尺寸的 testsizevisual 时,矩形和线条在屏幕上保持中心。但是,一旦我更改度量覆盖以返回巨大的尺寸,滚动就不再会导致图形正确居中。为什么一切都会在大尺寸下出现故障?我是否需要编写自己的滚动查看器来容纳大量内容,或者是否有解决方法?

WPF 是滚动查看器的水平偏移量,在较大值下准确

所以一个朋友终于为我想通了。即使我使用双精度进行计算,WPF 也会使用直接 x 进行绘图。直接 x 受浮点数限制。通过在维基上检查浮点数的尾数,我发现我超过了浮点数的尾数值,因此该值不再准确。