2

I currently have a custom Button control which displays a DrawingImage set on the control via a dependency property of type ControlTemplate. I have been attempting to move the DrawingImage into the control template and bind to a Geometry instead but have failed. Is it possible to bind to a Geometry object? If not why not, and if it is, what am I missing?

The screenshot below shows my successful attempt on the right and the failed attempt on the left.

The problem

Example of binding to a DrawingImage (which works) - generic.xaml:

<Style TargetType="{x:Type local:RoundButton3}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:RoundButton3}">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="auto"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>

                    <Ellipse StrokeThickness="5" Stroke="Green"/>

                    <Viewbox Margin="10" Stretch="Uniform">
                        <ContentControl 
                            Template="{TemplateBinding ImageTemplate}" />
                    </Viewbox>

                    <TextBlock VerticalAlignment="Center" 
                               Grid.Column="1" 
                               Text="Round Button" Margin="5,0,0,0" />
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

with

public class RoundButton3 : Button
{
    static RoundButton3()
    {
        DefaultStyleKeyProperty.OverrideMetadata(
            typeof(RoundButton3), 
            new FrameworkPropertyMetadata(typeof(RoundButton3)));
    }

    public static readonly DependencyProperty ImageTemplateProperty =
        DependencyProperty.Register(
            "ImageTemplate", typeof (ControlTemplate), typeof (RoundButton3),
            new FrameworkPropertyMetadata(
                default(ControlTemplate),
                FrameworkPropertyMetadataOptions.AffectsRender |
                FrameworkPropertyMetadataOptions.AffectsMeasure));

    public ControlTemplate ImageTemplate
    {
        get { return (ControlTemplate)GetValue(ImageTemplateProperty); }
        set { SetValue(ImageTemplateProperty, value); }
    }
}

and used like this

    <Grid.Resources>
        <GeometryGroup x:Key="AddGeometry">
            <LineGeometry StartPoint="25,12" EndPoint="25,38" />
            <LineGeometry StartPoint="12,25" EndPoint="38,25" />
        </GeometryGroup>

        <ControlTemplate x:Key="RoundAddTemplate">
            <Image SnapsToDevicePixels="True">
                <Image.Source>
                    <DrawingImage>
                        <DrawingImage.Drawing>
                            <DrawingGroup>
                                <GeometryDrawing Pen="{StaticResource RoundButtonPen}" Geometry="{StaticResource AddGeometry}"/>
                            </DrawingGroup>
                        </DrawingImage.Drawing>
                    </DrawingImage>
                </Image.Source>
            </Image>
        </ControlTemplate>
    </Grid.Resources>

   <local:RoundButton3 
        Grid.Column="1"
        Content="RoundButton3" ImageTemplate="{StaticResource RoundAddTemplate}"/>

My attempt at binding to a geometry resource (which doesn't work) - generic.xaml:

<Style TargetType="{x:Type local:RoundButton2}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:RoundButton2}">
                    ...

                    <Viewbox Margin="10" Stretch="Uniform">
                        <Image>
                            <Image.Source>
                                <DrawingImage>
                                    <DrawingImage.Drawing>
                                        <DrawingGroup>
                                            <DrawingGroup.Children>
                                                <GeometryDrawing 
                                                  Pen="{StaticResource RoundButtonPen}" 
                                                  Geometry="{TemplateBinding Geometry}" />
                                            </DrawingGroup.Children>
                                        </DrawingGroup>
                                    </DrawingImage.Drawing>
                                </DrawingImage>
                            </Image.Source>
                        </Image>
                    </Viewbox>

                    ...
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

where

public class RoundButton2 : Button
{
    static RoundButton2()
    {
        DefaultStyleKeyProperty.OverrideMetadata(
            typeof(RoundButton2), 
            new FrameworkPropertyMetadata(typeof(RoundButton2)));
    }

    #region Geometry

    public static readonly DependencyProperty GeometryProperty =
        DependencyProperty.Register(
            "Geometry", typeof (Geometry), typeof (RoundButton2),
            new FrameworkPropertyMetadata(
                default(Geometry),
                FrameworkPropertyMetadataOptions.AffectsRender | 
                FrameworkPropertyMetadataOptions.AffectsMeasure));

    public Geometry Geometry
    {
        get { return (Geometry)GetValue(GeometryProperty); }
        set { SetValue(GeometryProperty, value); }
    }

    #endregion
}

and used like

    <local:RoundButton2 
        Grid.Column="0"
        Geometry="{StaticResource AddGeometry}"
        Content="RoundButton2" />

using the AddGeometry resource defined earlier.

Phil
  • 42,255
  • 9
  • 100
  • 100

1 Answers1

5

Your code should work if you replace

<GeometryDrawing
    Geometry="{TemplateBinding Geometry}" />

by

<GeometryDrawing
    Geometry="{Binding Geometry, RelativeSource={RelativeSource TemplatedParent}}" />

See this question for an explanation.

Community
  • 1
  • 1
Clemens
  • 123,504
  • 12
  • 155
  • 268
  • Thanks, I tried everything apart from that :( Do you know why since I was under the impression TemplateBinding was equivalent to RelativeSource={RelativeSource TemplatedParent}? Ok, I'll look at http://stackoverflow.com/questions/1131222/wpf-templatebinding-vs-relativesource-templatedparent, that explains it. – Phil Mar 06 '12 at 20:56
  • See [here](http://stackoverflow.com/questions/1131222/wpf-templatebinding-vs-relativesource-templatedparent). – Clemens Mar 06 '12 at 20:57