Search code examples
wpfcustom-controlsrotatetransform

WPF usercontrol combine ellipse and arrow


I want to create a custom usercontrol to represent a player in a 2D map. I had an ellipse to represent the player but I want to have on the border of the ellipse an arrow to indicate where the player is looking.

This is what I tried :

<Ellipse Width="17" Height="17" Stroke="Black" Fill="White" HorizontalAlignment="Center" />
    <Path Data="M5,0 0,5 5,10" Fill="White" Stroke="Black" VerticalAlignment="Center" >
        <Path.LayoutTransform>
            <RotateTransform Angle="10"/>
        </Path.LayoutTransform>
    </Path>

the result : enter image description here

That looks like what I want (it's not properly aligned but that's not the point here).

The problems are :

  • I know the position of the ellipse's center without the arrow

  • When the arrow will be on the right the relative position of the ellipse's center will be different --> I could solve this problem using a square control

  • My Circle has a textblock on top (Horitonzal + vertical center) to display its id

How to move the arrow depending on the position looked ? I thought the easier might be to calculate an angle and rotate the whole control.

My first idea was to draw using any vector drawing software (illustrator for instance) the path, and get the coordinates of the path, and paste them in WPF.

then just rotate the usercontrol. But doing this will also rotate the text and I don't want the text to rotate.

I'm stuck on this one, I hope my problem is enough described to be understood.

EDIT My first try :

<ControlTemplate TargetType="ContentControl">
                        <Grid Width="34" Height="34">
                            <Path x:Name="contour_forme"
                              Stroke="{TemplateBinding BorderBrush}"
                              StrokeThickness="1"
                              Stretch="Uniform"
                              Width="28"
                              Height="22"
                              HorizontalAlignment="Left"
                              Fill="{TemplateBinding Background}"
                              Data="M28.857,53.500 C24.537,53.487 20.477,52.380 16.938,50.443 C16.938,50.443 16.938,50.500 16.938,50.500 C16.938,50.500 16.785,50.350 16.785,50.350 C12.845,48.157 9.579,44.924 7.317,41.032 C7.317,41.032 -6.176,27.755 -6.176,27.755 C-6.176,27.755 8.206,14.530 8.206,14.530 C10.380,11.316 13.289,8.649 16.681,6.736 C16.681,6.736 16.938,6.500 16.938,6.500 C16.938,6.500 16.938,6.581 16.938,6.581 C20.525,4.615 24.641,3.496 29.021,3.509 C42.835,3.551 53.996,14.775 53.951,28.580 C53.906,42.385 42.670,53.542 28.857,53.500 ZM29.004,8.507 C17.953,8.474 8.965,17.400 8.929,28.443 C8.893,39.487 17.822,48.467 28.873,48.500 C39.924,48.533 48.912,39.608 48.948,28.564 C48.985,17.520 40.056,8.540 29.004,8.507 Z"
                              >
                                <Path.LayoutTransform>
                                    <RotateTransform Angle="0" />
                                </Path.LayoutTransform>
                            </Path>
                            <TextBlock Style="{DynamicResource StyleTextes}" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center"
                                       Text="5"
                                       />
                        </Grid>
                    </ControlTemplate>

With the result :enter image description here As you can see I didn't manage to center the text inside my 22px circle. My arrow is about 6 px height so I've created a control of 22 (circle's size expected) + 2 * 6px depending on the arrow position.

But when I try to rotate my path doing :

<Path.LayoutTransform>         <RotateTransform Angle="90" />
                            </Path.LayoutTransform>

I have the following result : enter image description here

I'm not sure on how I can keep the circle of my path in the center of the control when I rotate the path.


Solution

  • Just apply the RotateTransform to the "image" but not to the text.
    Also I would use a render transform instead of a layout transform.

        <Canvas Canvas.Left="206.333" Canvas.Top="119" Height="80" Width="80">
        <Path Data="M244,99.333333 L210.16667,109.50034 244.83334,125.50034" Fill="#FFF4F4F5" Stretch="Fill" Stroke="Black"  RenderTransformOrigin="0.5,0.5" Height="60" Canvas.Left="3" Canvas.Top="5" Width="60">
            <Path.RenderTransform>
                <TransformGroup>
                    <ScaleTransform/>
                    <SkewTransform/>
                    <RotateTransform Angle="70"/>
                    <TranslateTransform/>
                </TransformGroup>
            </Path.RenderTransform>
        </Path>
        <TextBlock TextWrapping="Wrap" Text="TextBlock" Height="20" Width="80" Canvas.Top="30" TextAlignment="Center"/>
        </Canvas>