ControlTemplate not working as intended

697
2
Jump to solution
09-13-2012 11:10 AM
LuisGarcia2
Occasional Contributor II
I am creating some custom SimpleMarkerSymbol to be displayed on a GraphicsLayer. All I want is to display a marker with a black stroke (like shown in the attached shot) and indifferent shapes ("X", arrows, squares, rectangles and so on). I worked out the part of the black stroke in the ControlTemplate, so that is good. For the different shapes, I extended the "Shape" class from Microsoft and created my stuff. That all looks good except for one part. Our application has a slider that allows the user to increase/decrease the size of these Markers. My solution works well when I use the out of the box Ellipse; meaning that I can see the resizing happening and the bubbles increase/decrease in size and stay at the location defined by the MapPoint. However, when I do one of my Custom shapes and move the slider the Marker moves positions and does not changes size until I get it out of the viewing area and back in. Here is what I have for the Ellipse ControlTemplate (the one that WORKS fine):

<ControlTemplate x:Key="Circle">                     <Grid Name="RootElement" RenderTransformOrigin="0.5,0.5" >                         <Grid.RenderTransform>                             <ScaleTransform ScaleX="1" ScaleY="1" />                         </Grid.RenderTransform>                         <VisualStateManager.VisualStateGroups>                             <VisualStateGroup Name="CommonStates">                                 <VisualState Name="Normal">                                     <Storyboard>                                         <DoubleAnimation BeginTime="00:00:00"                                                                      Storyboard.TargetName="RootElement"                                                                      Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)"                                                                      To="1" Duration="0:0:0.1" />                                         <DoubleAnimation BeginTime="00:00:00"                                                                      Storyboard.TargetName="RootElement"                                                                      Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)"                                                                      To="1" Duration="0:0:0.1" />                                     </Storyboard>                                 </VisualState>                                 <VisualState Name="MouseOver">                                     <Storyboard>                                         <DoubleAnimation BeginTime="00:00:00"                                                                      Storyboard.TargetName="RootElement"                                                                      Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)"                                                                      To="1.5" Duration="0:0:0.1" />                                         <DoubleAnimation BeginTime="00:00:00"                                                                      Storyboard.TargetName="RootElement"                                                                      Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)"                                                                      To="1.5" Duration="0:0:0.1" />                                     </Storyboard>                                 </VisualState>                             </VisualStateGroup>                         </VisualStateManager.VisualStateGroups>                    <Ellipse Height="{Binding Symbol.Size}" Width="{Binding Symbol.Size}" Fill="{Binding Symbol.Color}" Stroke="Black">                                            </Ellipse>                 </Grid>             </ControlTemplate>


And this is what I have for my Arrow custom shape (the one that DOES NOT work). Basically the same thing but instead of the ellipse I have my Arrow class:

<ControlTemplate x:Key="Arrow">                     <Grid Name="RootElement" RenderTransformOrigin="0.5,0.5" >                         <Grid.RenderTransform>                             <ScaleTransform ScaleX="1" ScaleY="1" />                         </Grid.RenderTransform>                         <VisualStateManager.VisualStateGroups>                             <VisualStateGroup Name="CommonStates">                                 <VisualState Name="Normal">                                     <Storyboard>                                         <DoubleAnimation BeginTime="00:00:00"                                                                      Storyboard.TargetName="RootElement"                                                                      Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)"                                                                      To="1" Duration="0:0:0.1" />                                         <DoubleAnimation BeginTime="00:00:00"                                                                      Storyboard.TargetName="RootElement"                                                                      Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)"                                                                      To="1" Duration="0:0:0.1" />                                     </Storyboard>                                 </VisualState>                                 <VisualState Name="MouseOver">                                     <Storyboard>                                         <DoubleAnimation BeginTime="00:00:00"                                                                      Storyboard.TargetName="RootElement"                                                                      Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)"                                                                      To="1.5" Duration="0:0:0.1" />                                         <DoubleAnimation BeginTime="00:00:00"                                                                      Storyboard.TargetName="RootElement"                                                                      Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)"                                                                      To="1.5" Duration="0:0:0.1" />                                     </Storyboard>                                 </VisualState>                             </VisualStateGroup>                         </VisualStateManager.VisualStateGroups>                    <custom:Arrow Size="{Binding Symbol.Size}" Fill="{Binding Symbol.Color}"  Stroke="Black" RotationAngle="0">                     </custom:Arrow>                 </Grid>             </ControlTemplate>


And this is the extension of the Shape class, simply called Arrow:

public class Arrow : Shape     {         public Arrow() {          }           public static readonly DependencyProperty SizeProperty = DependencyProperty.Register("Size", typeof(Double), typeof(Arrow));         public static readonly DependencyProperty RotationAngleProperty = DependencyProperty.Register("RotationAngle", typeof(Double), typeof(Arrow), new PropertyMetadata(0.0d));          public double Size         {             get { return (double)this.GetValue(SizeProperty); }             set { this.SetValue(SizeProperty, value); }         }          public double RotationAngle         {             get { return (double)this.GetValue(RotationAngleProperty); }             set { this.SetValue(RotationAngleProperty, value); }         }          protected override Geometry DefiningGeometry         {             get             {                 double oneThird = this.Size / 3;                 double twoThirds = (this.Size * 2) / 3;                 double oneHalf = this.Size / 2;                  Point p1 = new Point(0.0d, oneThird);                 Point p2 = new Point(0.0d, twoThirds);                 Point p3 = new Point(oneHalf, twoThirds);                 Point p4 = new Point(oneHalf, this.Size);                  Point p5 = new Point(this.Size, oneHalf);                 Point p6 = new Point(oneHalf, 0);                 Point p7 = new Point(oneHalf, oneThird);                   List<PathSegment> segments = new List<PathSegment>(3);                 segments.Add(new LineSegment(p1, true));                 segments.Add(new LineSegment(p2, true));                 segments.Add(new LineSegment(p3, true));                 segments.Add(new LineSegment(p4, true));                  segments.Add(new LineSegment(p5, true));                 segments.Add(new LineSegment(p6, true));                 segments.Add(new LineSegment(p7, true));                  List<PathFigure> figures = new List<PathFigure>(1);                 PathFigure pf = new PathFigure(p1, segments, true);                 figures.Add(pf);                 RotateTransform rt = new RotateTransform(this.RotationAngle);                  Geometry g = new PathGeometry(figures, FillRule.EvenOdd, rt);                  return g;             }         }     }


I already changed the RenderTransformOrigin="0.5,0.5" position in the ControlTemplate and it still looks like it is moving to a different position. I also tried setting up the RotateTransform CenterX and CenterY variables to fixed points and did not work either. What am I missing? a Listener for the size?
0 Kudos
1 Solution

Accepted Solutions
DanielWalton
Occasional Contributor
I don't see how your Size DP connects to your DefiningGeometry. You should define the Size change handler to update it.

View solution in original post

0 Kudos
2 Replies
DanielWalton
Occasional Contributor
I don't see how your Size DP connects to your DefiningGeometry. You should define the Size change handler to update it.
0 Kudos
LuisGarcia2
Occasional Contributor II
I don't see how your Size DP connects to your DefiningGeometry. You should define the Size change handler to update it.


Yep, that was it. Thanks for your help. If someone is interested, this is how I solved it in the dependency property definition:

public static readonly DependencyProperty SizeProperty = DependencyProperty.Register("Size", typeof(Double), typeof(MapShape), new UIPropertyMetadata(new PropertyChangedCallback(SizeChanged)));


And then I added the handler:

        private static void SizeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            MapShape shape = (MapShape)d;
            shape.InvalidateVisual();        
        }


Thanks again!
0 Kudos