3
votes

I want to implement value converter to specify Point for RenderTransform. That works fine till I just implement IValueConverter interface. I know that I can implement MarkupExtension class to not to declare separated XAML Resource for my converter each time. When I try to implement this, I have

InvalidCastException: Unable to cast object of type 'System.Object' to type 'System.Windows.Data.IValueConverter'.

Converter implementation:

[ValueConversion(typeof(Point), typeof(Transform))]
public class PointToTransformConverter : MarkupExtension, IValueConverter
{
    private PointToTransformConverter _instance = null;

    public object Convert(
        object value, 
        Type targetType, 
        object parameter, 
        CultureInfo culture)
    {
        var point = (Point)value;

        return new TransformGroup
        {
            Children = new TransformCollection
            {
                new TranslateTransform(point.X, point.Y)
            }
        };
    }

    public object ConvertBack(
        object value, 
        Type targetType, 
        object parameter, 
        CultureInfo culture)
    {
        var transform = value as TransformGroup;
        if (transform?.Children.Count > 0)
        {
            var translateTransform = transform.Children[0] as TranslateTransform;
            if (translateTransform != null)
            {
                return new Point(
                    translateTransform.X, 
                    translateTransform.Y);
            }
        }

        return null;
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return _instance ?? (_instance = new PointToTransformConverter());
    }
}

XAML usage:

<local:PathControl x:Class="PathToWiringTube.PathView"
                   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                   xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                   xmlns:local="clr-namespace:PathToWiringTube"
                   xmlns:view="clr-namespace:PathToWiringTube.View"
                   xmlns:vm="clr-namespace:PathToWiringTube.VM"
                   xmlns:crocodile="clr-namespace:Crocodile;assembly=Crocodile"
                   mc:Ignorable="d" 
                   d:DataContext="{d:DesignInstance vm:PathVm}">
    <local:PathControl.Resources>
        <crocodile:PointToTransformConverter x:Key="pointToTransformConverter"/>
    </local:PathControl.Resources>
    <Canvas>
        <ItemsControl x:Name="itemsMarkers" ItemsSource="{Binding Markers}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <view:SplineDensityMarker Width="5" RenderTransform="{Binding Position, Converter={StaticResource pointToTransformConverter}}"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Canvas>
</local:PathControl>

What am I doing wrong?

2

2 Answers

2
votes

Could you please try the code below and check if the exception is coming? I have corrected it. The instance should be static and the xaml, you can directly refer to the converter instead of calling it as a static resource. That's the main use of using a MarkupExtension. The code below should work fine. If any issues, please revert.

Converter :

[ValueConversion(typeof(Point), typeof(Transform))]
public class PointToTransformConverter : MarkupExtension, IValueConverter
{
    private static PointToTransformConverter _instance = null;

    public object Convert(
        object value, 
        Type targetType, 
        object parameter, 
        CultureInfo culture)
    {
        var point = (Point)value;

        return new TransformGroup
        {
            Children = new TransformCollection
            {
                new TranslateTransform(point.X, point.Y)
            }
        };
    }

    public object ConvertBack(
        object value, 
        Type targetType, 
        object parameter, 
        CultureInfo culture)
    {
        var transform = value as TransformGroup;
        if (transform?.Children.Count > 0)
        {
            var translateTransform = transform.Children[0] as TranslateTransform;
            if (translateTransform != null)
            {
                return new Point(
                    translateTransform.X, 
                    translateTransform.Y);
            }
        }

        return null;
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return _instance ?? (_instance = new PointToTransformConverter());
    }
}

Xaml :

<local:PathControl x:Class="PathToWiringTube.PathView"
                   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                   xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                   xmlns:local="clr-namespace:PathToWiringTube"
                   xmlns:view="clr-namespace:PathToWiringTube.View"
                   xmlns:vm="clr-namespace:PathToWiringTube.VM"
                   xmlns:crocodile="clr-namespace:Crocodile;assembly=Crocodile"
                   mc:Ignorable="d" 
                   d:DataContext="{d:DesignInstance vm:PathVm}">
    </local:PathControl.Resources>
    <Canvas>
        <ItemsControl x:Name="itemsMarkers" ItemsSource="{Binding Markers}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <view:SplineDensityMarker Width="5" RenderTransform="{Binding Position, Converter={crocodile:PointToTransformConverter}}"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Canvas>
</local:PathControl>
0
votes

I've checked my code on another environment and detected that it works. I have done research for Visual Studio version mismatch and found out it (14.0.23107.0 D14REL and 14.0.24720.00 Update1). After installing the latest Visual Studio Update 2 on my old environment everything works fine.