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