Question

I have a control template that contains a path (besides other controls). The path should be resized when the control is resized. The points and the size that describe the path can be expressed as relativ fractions of the control size.

Here is an excerpt of the template:

<Path Stroke="Gray" StrokeThickness="5">
    <Path.Data>
        <PathGeometry>
            <PathFigure StartPoint="{TemplateBinding Start}" >
                <ArcSegment Point="{TemplateBinding End}" Size="{TemplateBinding Size}" RotationAngle="0" IsLargeArc="True" />
            </PathFigure>
        </PathGeometry>
    </Path.Data>
</Path>

Start and End are DependencyProperties of type Point, Size is a DependencyProperty of Type Size.

What I'm currently doing is listening to the FrameworkElement.SizeChanged event:

void OperationModeIndicator_SizeChanged( object sender, SizeChangedEventArgs e )
{
    this.Size = new Size( e.NewSize.Width * 0.45f, e.NewSize.Height * 0.45f );
    this.Start = new Point( e.NewSize.Width * 0.35f, e.NewSize.Height * 0.1f );
    this.End = new Point( e.NewSize.Width * 0.65f, e.NewSize.Height * 0.1f );
}

The question is now: Is there another (more elegant) way to bind the path's properties to the size of the parent control?

Was it helpful?

Solution

What you have is probably the best way to accomplish this.

Another way would be to build a custom IMultiValueConverter that exposes two public properties: WidthPercentage and HeightPercentage. Then you could bind to the ActualWidth/ActualHeight of the templated parent.

public class MyConverter : IMultiValueConverter {

    public double HeightPercentage { get; set; }
    public double WidthPercentage { get; set; }

    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) {
        // TODO: Validate values size and types

        return new Point(((double)values[0]) * this.WidthPercentage, ((double)values[1]) * this.HeightPercentage);
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) {
        // No-op or throw
    }

}

Which you'd use like:

<local:MyConverter x:Key="StartPointConverter"
    WidthPercentage="0.35" HeightPercentage="0.1" />

<!-- ... -->

<PathFigure>
    <PathFigure.StartPoint>
        <MultiBinding Converter="{StaticResource StartPointConverter}">
            <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="ActualWidth" />
            <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="ActualHeight" />
        </MultiBinding>
    </PathFigure.StartPoint>
    <!-- ... -->
</PathFigure>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top