WPF Path исчезает в некотором размере

Я столкнулся с этой проблемой при масштабировании графика, который рисуется поверх ГИС-элемента управления Greatmap. Но простой эксперимент убеждает меня, что проблемы где-то глубже в WPF.

Рассмотрим простое приложение WPF:

Это MainWindow.xaml

<Grid>
    <StackPanel>
        <Slider ValueChanged="Size_Changed" Minimum="0" Maximum="300000"/>
        <TextBox x:Name="Value"></TextBox>
    </StackPanel>
    <Canvas>
        <Path x:Name="MyPath" Stroke="Black" StrokeThickness="2" />
    </Canvas>
</Grid>

И это его код позади

private void Size_Changed(object sender,
        RoutedPropertyChangedEventArgs<double> e)
    {
        if (MyPath == null) return;

        var g = new StreamGeometry();
        using (var s = g.Open())
        {
            var pointA = new Point(0, 200);

            s.BeginFigure(pointA, false, false);

            var pointB = new Point(e.NewValue, 200);

            s.PolyLineTo(new[] {pointB}, true, true);

            Value.Text = $"zoom = {e.NewValue:0.0} ;  pointA = {pointA.X:#,0} ; pointB = {pointB.X:#,0}";
        }

        g.Freeze();

        MyPath.Data = g;
    }

Пока я перетаскиваю слайдер от 0 до 249999, все в порядке. Я вижу линию на моем взгляде. Но в тот момент значение ползунков становится 250000 - линия исчезает.

Есть ли ограничения в WPF?

Ответ 1

По какой-то причине лежащие в основе алгоритмы (это может быть Direct2D или его предок) учитывают отношение StrokeThickness/Geometry и решают, что штрих невидим в некоторой точке (1 против 125000). Это также несколько упомянуто здесь в этом другом вопросе: WPF DrawGeometry не рисует обводку.

Но обводка - это кисть, поэтому вы можете обмануть систему, используя эту кисть, например, в этом случае:

// use pen size instead of StrokeThickness
var geo = new GeometryDrawing(null, new Pen(Brushes.Black, 2), 
              new RectangleGeometry(new Rect(0, 0, e.NewValue, 1))); // use desired width for the geometry
var brush = new DrawingBrush(geo);
brush.Stretch = Stretch.None; // use this brush size, don't stretch to stroke thickness
brush.Freeze();
MyPath.Stroke = brush;

// choose a big number (more than desired thickness * 125000) to fool WPF or its friends
MyPath.StrokeThickness = 1000;

Ответ 2

Я не вижу никаких ограничений в WPF. Для меня это выглядит как ошибка WPF в рендеринге.

Я могу только предложить обходной путь, но я не знаю, почему это вызывает проблему после 250000. Я не знаю, применим ли этот обходной путь к вашему реальному случаю. Идея состоит в том, чтобы использовать LayoutTransform для рисования горизонтальной линии:

private void Size_Changed(object sender, RoutedPropertyChangedEventArgs<double> e)
{
    if (MyPath == null) return;

    var g = new StreamGeometry();
    using (var s = g.Open())
    {
        var pointA = new Point(0, 200);

        s.BeginFigure(pointA, false, false);

        var pointB = new Point(1, 200);

        s.PolyLineTo(new[] { pointB }, true, true);

        MyPath.LayoutTransform = new ScaleTransform(e.NewValue, 1);

        Value.Text = $"zoom = {e.NewValue:0.0} ;  pointA = {pointA.X:#,0} ; pointB = {pointB.X:#,0}";
    }

    g.Freeze();

    MyPath.Data = g;
}

Ответ 3

Очень захватывающая проблема, наверное, это ошибка. Если вы изменили точку A, как показано ниже:

var pointA = new Point(1, 200);

тогда это будет работать... :-)

Ответ 4

Похоже, это связано с проблемой, описанной в следующих горизонтальных или вертикальных линиях WPF, ограниченных 125 000 пикселей?

Похоже, что в WPF существует максимальное отношение длины к ширине обводки, относящееся к способу рендеринга графики, что может быть продиктовано рендерингом графики. При изменении ширины хода можно наблюдать следующее:

  • Если ширина хода равна 1: максимально допустимая длина составляет 125 000
  • Если ширина хода равна 2: максимально допустимая длина составляет 250 000
  • Если ширина хода равна 3: максимально допустимая длина составляет 375 000