1

The issue

I've got an application that tracks vehicles on a map. However I cannot get the little buggers to rotate in the direction of their motion. Basically, all of them are going sideways! Ugh!

Little icons of cars on a map

The code

Image vehicleImage = new Image
{
  //Set image size and source
};
RenderTransform rotation= new RotateTransform{Angle = X};
vehicleImage.RenderTransfrom = rotation; 
_mainMap.Children.Add(vehicleImage);
MapControl.SetLocation(vehicleImage, _position);

The Image, placed on the map, seems to completely ignore any angle I try to apply.

Vladimir Akopyan
  • 644
  • 8
  • 16

1 Answers1

5

To understand why the rotation doesn't take effect, let's first take a look at the image below, which is taken from the Live Visual Tree in Visual Studio -

enter image description here

I use a Rectangle but in your case, you will see your Image control there instead. When you insert it into the MapControl.Children collection, it will be wrapped with a special element called MapOverlayPresenter (as shown in the picture).

This MapOverlayPresenter is an internal element within MapControl and surprisingly, there's no official documentation on the Internet on what exactly it does. My guess is, as you zoom or rotate the map, this overlay simply responds by zooming or rotating in the opposite direction in order to maintain the original size and rotation of the child element, and this is causing the rotation transform of your inner Image to somehow get lost.

(P.S. RotationAngle and RotationAngleInDegrees from Composition have no effect here either.)


Solution

The way to work around this is simple - instead of exposing the rotation transform on the Image directly, create a UserControl called ImageControl which encapsulates this Image and its transform, with dependency properties like UriPath and Angle that are responsible for passing the information down to the inner Image and its CompositeTransform property.

The ImageControl XAML

<UserControl x:Class="App1.ImageControl" ...>
    <Image RenderTransformOrigin="0.5,0.5"
           Source="{x:Bind ConvertToBitmapImage(UriPath), Mode=OneWay}"
           Stretch="UniformToFill">
        <Image.RenderTransform>
            <CompositeTransform Rotation="{x:Bind Angle, Mode=OneWay}" />
        </Image.RenderTransform>
    </Image>
</UserControl>

The ImageControl code-behind

public string UriPath
{
    get => (string)GetValue(UriPathProperty);
    set => SetValue(UriPathProperty, value);
}
public static readonly DependencyProperty UriPathProperty = DependencyProperty.Register(
    "UriPath", typeof(string), typeof(ImageControl), new PropertyMetadata(default(string)));     

public double Angle
{
    get => (double)GetValue(AngleProperty);
    set => SetValue(AngleProperty, value);
}
public static readonly DependencyProperty AngleProperty = DependencyProperty.Register(
    "Angle", typeof(double), typeof(ImageControl), new PropertyMetadata(default(double)));

public BitmapImage ConvertToBitmapImage(string path) => new BitmapImage(new Uri(BaseUri, path));

How to use this ImageControl

var vehicleImage = new ImageControl
{
    Width = 80,
    UriPath = "/Assets/car.png",
    Angle = 45
};

_mainMap.Children.Add(vehicleImage);

Outcome

enter image description here

Hope this helps!

Justin XL
  • 38,763
  • 7
  • 88
  • 133
  • 1
    Awesome, detailed answer! Thanks for the help! – Vladimir Akopyan Jul 23 '17 at 16:07
  • Why it shows an error - "ConvertToBitmapImage" was not found in type ImageControl ? – user2431727 Jul 27 '18 at 11:09
  • @user2431727 you need to target 14393 or later to use function x:Bind. – Justin XL Jul 27 '18 at 22:19
  • my target is 10240. Can I pass a bitmapimage directly from vehicleImage? instead of uriPath ? – user2431727 Jul 30 '18 at 04:32
  • @user2431727 you just need to write a normal value converter instead. – Justin XL Jul 30 '18 at 04:33
  • I have done like below.but nothing happens.BitmapImage CarIconSource = new BitmapImage(new Uri("ms-appx:///Assets/car.png")); var vehicleImage = new ImageControl { Width = 80, UriPath= CarIconSource, Angle = 90 }; And datatype of UriPath in ImageControl codebehind changed to BitMapImage. Then this UriPath is passed to Source="{x:Bind UriPath, Mode=OneWay}" – user2431727 Jul 30 '18 at 04:44
  • @JustinXL I have opened a new thread in https://stackoverflow.com/questions/51557070/call-a-function-from-usercontrol-uwp-c-sharp?noredirect=1#comment90084298_51557070 – user2431727 Jul 30 '18 at 06:42