wpfCore3.1 binding mouse event to mvvm

essamce 621 Reputation points
2020-06-21T06:29:44.07+00:00

is there a way to bind xaml control mouse event to mouse event handler in viewmodel?
i'm using wpf core3.1 MS VS2019.

Developer technologies | Windows Presentation Foundation
0 comments No comments
{count} votes

Answer accepted by question author
  1. Peter Fleischer (former MVP) 19,341 Reputation points
    2020-06-21T18:51:17.893+00:00

    Hi, without seeing your code I cannot reproduce your problems. Try following demo:

    <Window x:Class="WpfApp1.Window03"  
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"  
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"  
            xmlns:local="clr-namespace:WpfApp03"  
            mc:Ignorable="d"  
            Title="Window03" Height="450" Width="400">  
      <Window.DataContext>  
        <local:ViewModel/>  
      </Window.DataContext>  
      <Grid>  
        <Grid.RowDefinitions>  
          <RowDefinition/>  
          <RowDefinition/>  
        </Grid.RowDefinitions>  
        <Viewport3D Grid.Row="0" local:ViewModel.Reference="True">  
          <Viewport3D.Camera>  
            <PerspectiveCamera Position="-40,40,40" LookDirection="40,-40,-40 "   
                             UpDirection="0,0,1" />  
          </Viewport3D.Camera>  
          <ModelVisual3D>  
            <ModelVisual3D.Content>  
              <Model3DGroup>  
                <DirectionalLight Color="White" Direction="-1,-1,-3" />  
                <GeometryModel3D>  
                  <GeometryModel3D.Geometry>  
                    <MeshGeometry3D Positions="0,0,0 10,0,0 10,10,0 0,10,0 0,0,10   
                            10,0,10 10,10,10 0,10,10"  
                            TriangleIndices="0 1 3 1 2 3  0 4 3 4 7 3  4 6 7 4 5 6   
                                             0 4 1 1 4 5  1 2 6 6 5 1  2 3 7 7 6 2"/>  
                  </GeometryModel3D.Geometry>  
                  <GeometryModel3D.Material>  
                    <DiffuseMaterial Brush="Red"/>  
                  </GeometryModel3D.Material>  
                </GeometryModel3D>  
              </Model3DGroup>  
            </ModelVisual3D.Content>  
          </ModelVisual3D>  
        </Viewport3D>  
        <Viewport3D Grid.Row="1" local:ViewModel.Reference="True">  
          <Viewport3D.Camera>  
            <PerspectiveCamera Position="-40,40,40" LookDirection="40,-40,-40 "   
                             UpDirection="0,0,1" />  
          </Viewport3D.Camera>  
          <ModelVisual3D>  
            <ModelVisual3D.Content>  
              <Model3DGroup>  
                <DirectionalLight Color="White" Direction="-1,-1,-3" />  
                <GeometryModel3D>  
                  <GeometryModel3D.Geometry>  
                    <MeshGeometry3D Positions="0,0,0 10,0,0 10,10,0 0,10,0 0,0,10   
                            10,0,10 10,10,10 0,10,10"  
                            TriangleIndices="0 1 3 1 2 3  0 4 3 4 7 3  4 6 7 4 5 6   
                                             0 4 1 1 4 5  1 2 6 6 5 1  2 3 7 7 6 2"/>  
                  </GeometryModel3D.Geometry>  
                  <GeometryModel3D.Material>  
                    <DiffuseMaterial Brush="Green"/>  
                  </GeometryModel3D.Material>  
                </GeometryModel3D>  
              </Model3DGroup>  
            </ModelVisual3D.Content>  
          </ModelVisual3D>  
        </Viewport3D>  
      </Grid>  
    </Window>  
      
    

    --------------------------------------

    using System;  
    using System.Collections.Generic;  
    using System.Linq;  
    using System.Windows;  
    using System.Windows.Controls;  
    using System.Windows.Input;  
    using System.Windows.Media.Media3D;  
      
    namespace WpfApp03  
    {  
      public class ViewModel  
      {  
      
        List<MyViewPort> ViewPorts = new List<MyViewPort>();  
      
        public static readonly DependencyProperty ReferenceProperty =  
          DependencyProperty.RegisterAttached("Reference", typeof(bool),  
                                              typeof(FrameworkElement),  
                                              new UIPropertyMetadata(false, OnReferenceChanged));  
        public static bool GetReference(DependencyObject obj) => (bool)obj.GetValue(ReferenceProperty);  
        public static void SetReference(DependencyObject obj, bool value) => obj.SetValue(ReferenceProperty, value);  
      
        private static void OnReferenceChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)  
        {  
          var vp = depObj as Viewport3D;  
          if (vp == null || !(e.NewValue is Boolean)) return;  
          var vm = vp.DataContext as ViewModel;  
          if (vm.ViewPorts.Count == 0 || vm.ViewPorts.Where((v) => v.VPort == vp).Count() == 0)  
            vm.ViewPorts.Add(new MyViewPort() { VPort = vp });  
        }  
      }  
      
      public class MyViewPort  
      {  
        private Viewport3D _vPort;  
        public Viewport3D VPort  
        {  
          get => this._vPort;  
          set  
          {  
            if (this._vPort == null)  
            {  
              this._vPort = value;  
              this._vPort.MouseDown += _vPort_MouseDown;  
              this._vPort.MouseMove += _vPort_MouseMove;  
              this._vPort.MouseUp += _vPort_MouseUp;  
              this._vPort.Loaded += _vPort_Loaded;  
            }  
          }  
        }  
      
        private AxisAngleRotation3D rot = new AxisAngleRotation3D(new Vector3D(0, 2, 0), 0);  
        private void _vPort_Loaded(object sender, RoutedEventArgs e)  
        {  
          var mod = this._vPort.Children[0] as ModelVisual3D;  
          mod.Transform = new RotateTransform3D(rot);  
        }  
      
        private Point pt = new Point(double.NaN, double.NaN);  
        private void _vPort_MouseDown(object sender, MouseButtonEventArgs e) =>       pt = e.GetPosition(this._vPort);  
        private void _vPort_MouseMove(object sender, MouseEventArgs e)  
        {  
          if (!double.IsNaN(pt.X))  
          {  
            Point pt1 = e.GetPosition(this._vPort);  
            double ang = pt1.X - pt.X;  
            rot.Angle = ang;  
          }  
        }  
        private void _vPort_MouseUp(object sender, MouseButtonEventArgs e)=>       pt = new Point(double.NaN, double.NaN);  
      }  
    }  
    

    10462-21-06-2020-20-47-36.gif

    1 person found this answer helpful.

1 additional answer

Sort by: Most helpful
  1. Peter Fleischer (former MVP) 19,341 Reputation points
    2020-06-21T07:43:38.717+00:00

    Hi, you can use "attached property" pattern like in following demo:

    <Window x:Class="WpfApp1.Window02"  
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"  
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"  
            xmlns:local="clr-namespace:WpfApp02"  
            mc:Ignorable="d"  
            Title="Window02" Height="450" Width="800">  
      <Window.DataContext>  
        <local:ViewModel/>  
      </Window.DataContext>  
      <Grid>  
        <ListBox ItemsSource="{Binding Log}" local:ViewModel.MouseEvents="True"/>  
      </Grid>  
    </Window>      
    

    ----------------------------------------------------------

    using System;  
    using System.Collections.ObjectModel;  
    using System.Windows;  
      
    namespace WpfApp02  
    {  
      public class ViewModel   
      {  
        public ObservableCollection<string> Log { get; set; } = new ObservableCollection<string>();  
        public void InsertLogEntry(string msg) => Log.Insert(0, msg);  
      
        public static readonly DependencyProperty MouseEventsProperty =  
          DependencyProperty.RegisterAttached("MouseEvents", typeof(bool),  
                                              typeof(FrameworkElement),  
                                              new UIPropertyMetadata(false, OnMouseEventsChanged));  
        public static bool GetMouseEvents(DependencyObject obj) => (bool)obj.GetValue(MouseEventsProperty);  
        public static void SetMouseEvents(DependencyObject obj, bool value) => obj.SetValue(MouseEventsProperty, value);  
      
        private static void OnMouseEventsChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)  
        {  
          var fwe = depObj as FrameworkElement;  
          if (fwe == null || !(e.NewValue is Boolean)) return;  
          if ((bool)(e.NewValue)) fwe.MouseDown += OnMouseDown;  
          else fwe.MouseDown -= OnMouseDown;  
        }  
      
        private static void OnMouseDown(object sender, EventArgs e)  
        {  
          var uie = sender as FrameworkElement;  
          var vm = uie.DataContext as ViewModel;  
          vm.InsertLogEntry($"MouseDown: {DateTime.Now:HH:mm:ss.fff}");  
        }  
      }  
    }  
    

    10426-21-06-2020-09-44-36.gif

    1 person found this answer helpful.

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.