Reputation: 6796
I have a series of shape-related view-model classes. Your typical traditional hierarchy: Base ShapeVm class, then LineVm, CircleVm, etc. Each exposes a Geometry property of the appropriate type.
public abstract class ShapeVm
{
public abstract Geometry Geometry { get; }
}
public class LineVm : ShapeVm
{
public override Geometry Geometry => new LineGeometry(P1, P2);
public Point P1 { get; set; }
public Point P2 { get; set; }
}
Until now I've exposed these in XAML using the same type, Path, regardless of the shape type.
<Path Fill="Yellow" StrokeThickness="3" Data={Binding Geometry}"/>
But now I want to be able to apply a transform to each PathGeometry in XAML. That is causing me problems of a "making-my-code-smell" nature:
My approach is to to manually construct my Path object's PathGeometry in XAML and set its Transform property. But I cannot figure out how to cleanly make all the various Geometry types (LineGeometry, EllipseGeometry, etc) easily convert to PathGeometry. I need to supply a "Figures" property to the PathGeometry.
<Path Fill="Yellow" Stroke="Blue" StrokeThickness="3">
<Path.Data>
<PathGeometry Figures="???" **** WHAT DO I USE HERE??? ***
Transform="{Binding MyViewGeoTransform}"/>
</Path.Data>
</Path>
The PathGeometry.Figures property is of type PathFigureCollection. Is there a built-in converter somewhere that converts any old WPF Geometry to PathFigureCollection? System.Windows.Media.GeometryConverter does not appear to do the trick.
Is there some obvious easy way to do this that I am missing? Should I just write my converter?
(I realize I could just write a different data template for each shape type and will do that if it's cleanest but using just one Path object in XAML appeals to my sense of simplicity)
Upvotes: 0
Views: 585
Reputation: 128062
The most simple approach to a apply a Transform to the Path would perhaps be to set its RenderTransform
property:
<Path Fill="Yellow" StrokeThickness="3"
Data="{Binding Geometry}"
RenderTransformOrigin="0.5,0.5"
RenderTransform="{Binding MyViewGeoTransform}"/>
If that is for any reason not desirable, you could use a MultiBinding with a converter that creates a transformed GeometryGroup:
<Path Fill="Yellow" StrokeThickness="3">
<Path.Data>
<MultiBinding Converter="{StaticResource TransformedGeometryConverter}">
<Binding Path="Geometry"/>
<Binding Path="MyViewGeoTransform"/>
</MultiBinding>
</Path.Data>
</Path>
The converter:
public class TransformedGeometryConverter : IMultiValueConverter
{
public object Convert(
object[] values, Type targetType, object parameter, CultureInfo culture)
{
var geometry = new GeometryGroup { Transform = (Transform)values[1] };
geometry.Children.Add((Geometry)values[0]);
return geometry;
}
public object[] ConvertBack(
object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
Upvotes: 1