Cristian Henrici
Cristian Henrici

Reputation: 7

Passing MouseEvent Args in MVVM Light

I am programming an application where I can crop and resize an image by mouse. Because I had problems figuring out how I could pass Event Args in MVVM, I decided to give MVVM Light a try. Now everytime my mouse is over the image I receive the error:

An unhandled exception of type 'System.InvalidCastException' occurred in GalaSoft.MvvmLight.Platform.dll

Additional information: Das Objekt des Typs "System.Windows.Point" kann nicht in Typ "System.Windows.Input.MouseEventArgs" umgewandelt werden.

I don't really know how to fix this although I assume that my RelayCommands are implemented wrong.

I did the bindings in the XAML as following:

 <Image x:Name="_image" Margin="10" Source="{Binding CurrentImage.ImagePath, UpdateSourceTrigger=PropertyChanged}"
               HorizontalAlignment="Left" VerticalAlignment="Top" Stretch="Fill" MaxHeight="300">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="MouseDown">
                    <cmd:EventToCommand Command="{Binding Mode=OneWay, Path=MouseDownCommand}"
                                        EventArgsConverter="{StaticResource MouseButtonEventArgsToPointConverter}"
                                        EventArgsConverterParameter="{Binding ElementName=_image}"
                                        PassEventArgsToCommand="True" />
                </i:EventTrigger>
                <i:EventTrigger EventName="MouseMove">
                    <cmd:EventToCommand Command="{Binding Mode=OneWay, Path=MouseMoveCommand}"
                                        EventArgsConverter="{StaticResource MouseEventArgsToPointConverter}"
                                        EventArgsConverterParameter="{Binding ElementName=_image}"
                                        PassEventArgsToCommand="True" />
                </i:EventTrigger>
                <i:EventTrigger EventName="MouseUp">
                    <cmd:EventToCommand Command="{Binding Mode=OneWay, Path=MouseUpCommand}"
                                        EventArgsConverter="{StaticResource MouseButtonEventArgsToPointConverter}"
                                        EventArgsConverterParameter="{Binding ElementName=_image}"
                                        PassEventArgsToCommand="True" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Image>

My ViewModel looks like this:

RelayCommand<MouseButtonEventArgs> mouseDownCommand;
    public RelayCommand<MouseButtonEventArgs> MouseDownCommand
    {
        get
        {
            if (mouseDownCommand == null)
            {
                mouseDownCommand = new RelayCommand<MouseButtonEventArgs>(MouseDown);
            }
            return mouseDownCommand;
        }
    }

    public void MouseDown(MouseButtonEventArgs e)
    {
        this.currentImage.StartPoint = e.GetPosition(this.currentImage.CnvImage);
    }

    RelayCommand<System.Windows.Input.MouseEventArgs> mouseMoveCommand;
    public RelayCommand<System.Windows.Input.MouseEventArgs> MouseMoveCommand
    {
      get
        {
            if (mouseMoveCommand == null)
            {
                mouseMoveCommand = new RelayCommand<System.Windows.Input.MouseEventArgs>(MouseMove);
            }
            return mouseMoveCommand;
        }
    }

    public void MouseMove(System.Windows.Input.MouseEventArgs e)
    {
        if (e.LeftButton == MouseButtonState.Pressed)
        {
            var pos = e.GetPosition(this.currentImage.CnvImage);

            var x = Math.Min(pos.X, this.currentImage.StartPoint.X);
            var y = Math.Min(pos.Y, this.currentImage.StartPoint.Y);

            var w = Math.Max(pos.X, this.currentImage.StartPoint.X) - x;
            var h = Math.Max(pos.Y, this.currentImage.StartPoint.Y) - y;

            var rect = new System.Windows.Shapes.Rectangle
            {
                Stroke = System.Windows.Media.Brushes.LightBlue,
                StrokeThickness = 2
            };

            this.currentImage.RectSelectArea = rect;

            this.currentImage.RectSelectArea.Width = w;
            this.currentImage.RectSelectArea.Height = h;

            Canvas.SetLeft(this.currentImage.RectSelectArea, x);
            Canvas.SetTop(this.currentImage.RectSelectArea, y);
        }
    }

    RelayCommand<MouseButtonEventArgs> mouseUpCommand;
    public RelayCommand<MouseButtonEventArgs> MouseUpCommand
    {
       get
        {
            if (mouseUpCommand == null)
            {
                mouseUpCommand = new RelayCommand<MouseButtonEventArgs>(MouseUp);
            }
            return mouseUpCommand;
        }
    }

    public void MouseUp(MouseButtonEventArgs e)
    {
        System.Windows.Controls.Image croppedImage = new System.Windows.Controls.Image();
        croppedImage.Width = 100;
        croppedImage.Margin = new Thickness(5);

        this.currentImage.CropXPosition = (int)this.currentImage.StartPoint.X;
        this.currentImage.CropYPosition = (int)this.currentImage.StartPoint.Y;
        this.currentImage.CropWidth = (int)this.currentImage.RectSelectArea.Width;
        this.currentImage.CropHeight = (int)this.currentImage.RectSelectArea.Height;
        CroppedBitmap cb = new CroppedBitmap(
            (BitmapSource)this.currentImage.ImagePath, new Int32Rect(
                this.currentImage.CropXPosition, this.currentImage.CropYPosition, this.currentImage.CropWidth, this.currentImage.CropHeight));
        croppedImage.Source = cb;
    }

The MouseButtonEventToArgsToPointConverter:

  class MouseButtonEventArgsToPointConverter : IEventArgsConverter
{
    public object Convert(object value, object parameter)
    {
        var args = (MouseButtonEventArgs)value;
        var element = (FrameworkElement)parameter;

        var point = args.GetPosition(element);
        return point;
    }
}

I also followed this advice from a similar question if not same question, but the RelayCommand won't work as a type Point. How can I fix this? Or is my approach wrong? Really thankful for any kind of help or suggestions.

Upvotes: 0

Views: 1391

Answers (1)

Tim Rutter
Tim Rutter

Reputation: 4679

You are converting the MouseButtonEventArgs to a Point in the MouseButtonEventArgsToPointConverter but the commands are expecting a MouseButtonEventArgs parameter - hence the cast exception. You convert it to a Point and then the Point is passed to the RelayCommand<MouseButtonEventArgs>, an attempt is then made to cast Point to MouseButtonEventArgs which it obviously cannot do. Do you want to pass the Point or the event args? If point then change the command to RelayCommand<Point>, if event args then remove use of the converter

Either:

 <cmd:EventToCommand Command="{Binding Mode=OneWay, 
    Path=MouseDownCommand}"                                        
    EventArgsConverter="{StaticResource MouseButtonEventArgsToPointConverter}"                                         
    EventArgsConverterParameter="{Binding ElementName=_image}"
    PassEventArgsToCommand="True" />

public RelayCommand<Point> MouseDownCommand
{
    get
    {
       ...
    }
}

Also in this case you need to change MouseDown to this:

public void MouseDown(Point p)

Or:

<cmd:EventToCommand Command="{Binding Mode=OneWay, 
    Path=MouseDownCommand}"  PassEventArgsToCommand="True" />

public RelayCommand<MouseButtonEventArgs> MouseDownCommand
{
    get
    {
        ...
    }
}

Upvotes: 1

Related Questions