StrokeStartLineCap not set when PathGeometry is bound
-
02-07-2021 - |
Question
XAML produces the expected result: a line with rounded ends.
However, data binding the same PathGeometry produces flat ends. I'm not sure why this is, can anyone explain?
Here is a simplified example:
XAML:
<Grid>
<Path Fill="Green" Stroke="Black" StrokeThickness="8"
Stretch="None" IsHitTestVisible="False"
Data="{Binding IndicatorGeometry}"
StrokeStartLineCap="Round" StrokeEndLineCap="Round"/>
<!--<Path Fill="Green" Stroke="Black" StrokeThickness="8"
Stretch="None" IsHitTestVisible="False"
StrokeStartLineCap="Round" StrokeEndLineCap="Round">
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="64,64">
<LineSegment Point="128,8"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>-->
</Grid>
C#:
private static PathFigure[] ms_figure = new []
{
new PathFigure(
new Point(64, 64),
new[]
{
new LineSegment(new Point(128, 8), false)
},
true)
};
public PathGeometry IndicatorGeometry
{
get { return (PathGeometry)GetValue(IndicatorGeometryProperty); }
set { SetValue(IndicatorGeometryProperty, value); }
}
public static readonly DependencyProperty IndicatorGeometryProperty =
DependencyProperty.Register("IndicatorGeometry", typeof(PathGeometry), typeof(MainWindow),
new FrameworkPropertyMetadata(new PathGeometry(ms_figure)));
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
Solution
If you compare the Geometry
created by the XAML to the one created in code behind, then they are different.
The code-behind one has a number of differences...it uses "z" to close the Path, while your XAML one doesn't...also one had a PathFigureCollection the other didn't....also it set the freezable property to true.
You need to try and build the one in the code-behind to be the same as the XAML produced one...it seems like its a lot of work to build the Geometry to match.
I've come up with an alternative way to build the Geometry which works...hopefully this helps in your case.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApplication4
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private static Geometry m_DefaultIndicatorGeometry = Geometry.Parse("M 64,64 L 128,8");
public Geometry IndicatorGeometry
{
get { return (Geometry)GetValue(IndicatorGeometryProperty); }
set { SetValue(IndicatorGeometryProperty, value); }
}
public static readonly DependencyProperty IndicatorGeometryProperty =
DependencyProperty.Register("IndicatorGeometry", typeof(Geometry), typeof(MainWindow),
new FrameworkPropertyMetadata(m_DefaultIndicatorGeometry));
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
}
}
You could alternatively just use a string as the property, because the Data property has a TypeConverter to convert a string that describes a Path using the Path Markup Syntax into a Geometry.
public partial class MainWindow : Window
{
private static string m_DefaultIndicatorGeometry = "M 64,64 L 128,8";
public string IndicatorGeometry
{
get { return (string)GetValue(IndicatorGeometryProperty); }
set { SetValue(IndicatorGeometryProperty, value); }
}
public static readonly DependencyProperty IndicatorGeometryProperty =
DependencyProperty.Register("IndicatorGeometry", typeof(string), typeof(MainWindow),
new FrameworkPropertyMetadata(m_DefaultIndicatorGeometry));
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
}