WPF MouseWheel MouseDown MouseUp MouseMove mapped in mvvm via behavior

//xaml
<Window x:Class="WpfApp201.MainWindow"
        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:behavior="http://schemas.microsoft.com/xaml/behaviors"
        xmlns:local="clr-namespace:WpfApp201"
        mc:Ignorable="d" WindowState="Maximized"
        Title="{Binding MainTitle,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" 
        Height="450" Width="800">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="200"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <ListBox x:Name="lbx" Grid.Column="0"                  
                 ItemsSource="{Binding BooksList,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                 SelectedIndex="{Binding SelectedIdx,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
                 SelectedItem="{Binding SelectedBook,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" >
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Image Source="{Binding ImgUrl}" Width="200" Height="500" 
                           RenderOptions.BitmapScalingMode="LowQuality"/>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <Image x:Name="img" Grid.Column="1" Source="{Binding SelectedItem.ImgUrl,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,ElementName=lbx}"
               ClipToBounds="True">
            <behavior:Interaction.Triggers>
                <behavior:EventTrigger EventName="MouseWheel">
                    <behavior:CallMethodAction TargetObject="{Binding}" MethodName="Image_MouseWheel"/>
                </behavior:EventTrigger>
                <behavior:EventTrigger EventName="MouseDown">
                    <behavior:CallMethodAction TargetObject="{Binding}" MethodName="img_MouseDown"/>
                </behavior:EventTrigger>
                <behavior:EventTrigger EventName="MouseUp">
                    <behavior:CallMethodAction TargetObject="{Binding}" MethodName="img_MouseUp"/>
                </behavior:EventTrigger>
                <behavior:EventTrigger EventName="MouseMove">
                    <behavior:CallMethodAction TargetObject="{Binding}" MethodName="img_MouseMove"/>
                </behavior:EventTrigger>
            </behavior:Interaction.Triggers>
            <Image.RenderTransform>
                <TransformGroup>
                    <ScaleTransform />
                    <TranslateTransform />
                </TransformGroup>
            </Image.RenderTransform>
        </Image>
    </Grid>
</Window>


//cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;

namespace WpfApp201
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            var vm = new BookVM();
            this.DataContext = vm;
        }
    }

    public class BookVM : INotifyPropertyChanged
    {
        public BookVM()
        {
            InitData();
            InitTimer();
        }

        private void InitTimer()
        {
            System.Timers.Timer tm = new System.Timers.Timer();
            tm.Elapsed += Tm_Elapsed;
            tm.Interval = 100;
            //tm.Start();
        }

        private void Tm_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (++SelectedIdx >= BooksList.Count)
            {
                SelectedIdx = 0;
            }
        }

        private void InitData()
        {
            var imgsList = Directory.GetFiles(@"..\..\Images");
            if (imgsList != null && imgsList.Any())
            {
                BooksList = new List<Book>();
                int len = imgsList.Count();
                for (int i = 0; i < 100000; i++)
                {
                    BooksList.Add(new Book()
                    {
                        Id = i + 1,
                        ImgUrl = imgsList[i % len]
                    });
                }
                SelectedBook = BooksList[0];
            }
        }

        public void img_MouseDown(object sender, MouseButtonEventArgs e)
        {
            var image = sender as Image;
            if (image != null)
            {
                CurrentPt = e.GetPosition(image);
            }
        }

        public void img_MouseUp(object sender, MouseButtonEventArgs e)
        {
            var image = sender as Image;
            if (image != null && isMoving && e.ChangedButton == MouseButton.Left && e.ButtonState == MouseButtonState.Released)
            {
                var transformGroup = image.RenderTransform as TransformGroup;
                if (transformGroup != null)
                {
                    foreach (var child in transformGroup.Children)
                    {
                        var translater = child as TranslateTransform;
                        if (translater != null)
                        {
                            var pt = e.GetPosition(image);
                            translater.X += pt.X - CurrentPt.X;
                            translater.Y += pt.Y - CurrentPt.Y;
                            break;
                        } 
                    }
                }
            }
        }

        public void img_MouseMove(object sender, MouseEventArgs e)
        {
            var image = sender as Image;
            if (image != null)
            {
                isMoving = true;
            }
        }

        public void Image_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            //new System.Linq.SystemCore_EnumerableDebugView<System.Windows.Media.Transform>(((System.Windows.Media.TransformGroup)image.RenderTransform).Children).Items[0]
            var image = sender as Image;
            if (image != null)
            {
                var transformGroup = image.RenderTransform as TransformGroup;
                if (transformGroup != null)
                {
                    foreach (var child in transformGroup.Children)
                    {
                        var scaler = child as ScaleTransform;
                        if (scaler != null)
                        {
                            if (e.Delta > 0)
                            {
                                scaler.ScaleX *= 1.2;
                                scaler.ScaleY *= 1.2;
                            }
                            else
                            {
                                scaler.ScaleX /= 1.2;
                                scaler.ScaleY /= 1.2;
                            }
                            scaler.CenterX = e.GetPosition(image).X;
                            scaler.CenterY = e.GetPosition(image).Y;
                            break;
                        }
                    }
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string propName)
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                handler?.Invoke(this, new PropertyChangedEventArgs(propName));
            }
        }

        private bool isMoving = false;

        private Point currentPt;
        public Point CurrentPt
        {
            get
            {
                return currentPt;
            }
            set
            {
                if (value != currentPt)
                {
                    currentPt = value;
                    OnPropertyChanged(nameof(CurrentPt));
                }
            }
        }

        private int selectedIdx;
        public int SelectedIdx
        {
            get
            {
                return selectedIdx;
            }
            set
            {
                if (value != selectedIdx)
                {
                    selectedIdx = value;
                    OnPropertyChanged(nameof(SelectedIdx));
                }
            }
        }

        private Book selectedBook;
        public Book SelectedBook
        {
            get
            {
                return selectedBook;
            }
            set
            {
                if (value != selectedBook)
                {
                    selectedBook = value;
                    OnPropertyChanged(nameof(SelectedBook));
                    MainTitle = SelectedBook?.ToString();
                }
            }
        }

        private List<Book> booksList;
        public List<Book> BooksList
        {
            get
            {
                return booksList;
            }
            set
            {
                if (value != booksList)
                {
                    booksList = value;
                    OnPropertyChanged(nameof(BooksList));
                }
            }
        }

        private string mainTitle;
        public string MainTitle
        {
            get
            {
                return mainTitle;
            }
            set
            {
                mainTitle = value;
                OnPropertyChanged(nameof(MainTitle));
            }
        }
    }

    public class Book
    {
        public int Id { get; set; }

        public string ImgUrl { get; set; }

        public override string ToString()
        {
            return $"{Id},{System.IO.Path.GetFullPath(ImgUrl)}";
        }
    }

}

 

 

Key part

<Image x:Name="img" Grid.Column="1" Source="{Binding SelectedItem.ImgUrl,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,ElementName=lbx}"
       ClipToBounds="True">
    <behavior:Interaction.Triggers>
        <behavior:EventTrigger EventName="MouseWheel">
            <behavior:CallMethodAction TargetObject="{Binding}" MethodName="Image_MouseWheel"/>
        </behavior:EventTrigger>
        <behavior:EventTrigger EventName="MouseDown">
            <behavior:CallMethodAction TargetObject="{Binding}" MethodName="img_MouseDown"/>
        </behavior:EventTrigger>
        <behavior:EventTrigger EventName="MouseUp">
            <behavior:CallMethodAction TargetObject="{Binding}" MethodName="img_MouseUp"/>
        </behavior:EventTrigger>
        <behavior:EventTrigger EventName="MouseMove">
            <behavior:CallMethodAction TargetObject="{Binding}" MethodName="img_MouseMove"/>
        </behavior:EventTrigger>
    </behavior:Interaction.Triggers>
    <Image.RenderTransform>
        <TransformGroup>
            <ScaleTransform />
            <TranslateTransform />
        </TransformGroup>
    </Image.RenderTransform>
</Image>

 

 

  public void img_MouseDown(object sender, MouseButtonEventArgs e)
  {
      var image = sender as Image;
      if (image != null)
      {
          CurrentPt = e.GetPosition(image);
      }
  }

  public void img_MouseUp(object sender, MouseButtonEventArgs e)
  {
      var image = sender as Image;
      if (image != null && isMoving && e.ChangedButton == MouseButton.Left && e.ButtonState == MouseButtonState.Released)
      {
          var transformGroup = image.RenderTransform as TransformGroup;
          if (transformGroup != null)
          {
              foreach (var child in transformGroup.Children)
              {
                  var translater = child as TranslateTransform;
                  if (translater != null)
                  {
                      var pt = e.GetPosition(image);
                      translater.X += pt.X - CurrentPt.X;
                      translater.Y += pt.Y - CurrentPt.Y;
                      break;
                  } 
              }
          }
      }
  }

  public void img_MouseMove(object sender, MouseEventArgs e)
  {
      var image = sender as Image;
      if (image != null)
      {
          isMoving = true;
      }
  }

  public void Image_MouseWheel(object sender, MouseWheelEventArgs e)
  {
      //new System.Linq.SystemCore_EnumerableDebugView<System.Windows.Media.Transform>(((System.Windows.Media.TransformGroup)image.RenderTransform).Children).Items[0]
      var image = sender as Image;
      if (image != null)
      {
          var transformGroup = image.RenderTransform as TransformGroup;
          if (transformGroup != null)
          {
              foreach (var child in transformGroup.Children)
              {
                  var scaler = child as ScaleTransform;
                  if (scaler != null)
                  {
                      if (e.Delta > 0)
                      {
                          scaler.ScaleX *= 1.2;
                          scaler.ScaleY *= 1.2;
                      }
                      else
                      {
                          scaler.ScaleX /= 1.2;
                          scaler.ScaleY /= 1.2;
                      }
                      scaler.CenterX = e.GetPosition(image).X;
                      scaler.CenterY = e.GetPosition(image).Y;
                      break;
                  }
              }
          }
      }
  }

 

 

 

 

 

 

 

 

 

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Windows;

namespace Microsoft.Xaml.Behaviors.Core;

public class CallMethodAction : TriggerAction<DependencyObject>
{
    private class MethodDescriptor
    {
        public MethodInfo MethodInfo { get; private set; }

        public bool HasParameters => Parameters.Length != 0;

        public int ParameterCount => Parameters.Length;

        public ParameterInfo[] Parameters { get; private set; }

        public Type SecondParameterType
        {
            get
            {
                if (Parameters.Length >= 2)
                {
                    return Parameters[1].ParameterType;
                }
                return null;
            }
        }

        public MethodDescriptor(MethodInfo methodInfo, ParameterInfo[] methodParams)
        {
            MethodInfo = methodInfo;
            Parameters = methodParams;
        }
    }

    private List<MethodDescriptor> methodDescriptors;

    public static readonly DependencyProperty TargetObjectProperty = DependencyProperty.Register("TargetObject", typeof(object), typeof(CallMethodAction), new PropertyMetadata(OnTargetObjectChanged));

    public static readonly DependencyProperty MethodNameProperty = DependencyProperty.Register("MethodName", typeof(string), typeof(CallMethodAction), new PropertyMetadata(OnMethodNameChanged));

    public object TargetObject
    {
        get
        {
            return GetValue(TargetObjectProperty);
        }
        set
        {
            SetValue(TargetObjectProperty, value);
        }
    }

    public string MethodName
    {
        get
        {
            return (string)GetValue(MethodNameProperty);
        }
        set
        {
            SetValue(MethodNameProperty, value);
        }
    }

    private object Target => TargetObject ?? base.AssociatedObject;

    public CallMethodAction()
    {
        methodDescriptors = new List<MethodDescriptor>();
    }

    protected override void Invoke(object parameter)
    {
        if (base.AssociatedObject == null)
        {
            return;
        }
        MethodDescriptor methodDescriptor = FindBestMethod(parameter);
        if (methodDescriptor != null)
        {
            ParameterInfo[] parameters = methodDescriptor.Parameters;
            if (parameters.Length == 0)
            {
                methodDescriptor.MethodInfo.Invoke(Target, null);
            }
            else if (parameters.Length == 2 && base.AssociatedObject != null && parameter != null && parameters[0].ParameterType.IsAssignableFrom(base.AssociatedObject.GetType()) && parameters[1].ParameterType.IsAssignableFrom(parameter.GetType()))
            {
                methodDescriptor.MethodInfo.Invoke(Target, new object[2] { base.AssociatedObject, parameter });
            }
        }
        else if (TargetObject != null)
        {
            throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, ExceptionStringTable.CallMethodActionValidMethodNotFoundExceptionMessage, MethodName, TargetObject.GetType().Name));
        }
    }

    protected override void OnAttached()
    {
        base.OnAttached();
        UpdateMethodInfo();
    }

    protected override void OnDetaching()
    {
        methodDescriptors.Clear();
        base.OnDetaching();
    }

    private MethodDescriptor FindBestMethod(object parameter)
    {
        if (parameter != null)
        {
            parameter.GetType();
        }
        return methodDescriptors.FirstOrDefault((MethodDescriptor methodDescriptor) => !methodDescriptor.HasParameters || (parameter != null && methodDescriptor.SecondParameterType.IsAssignableFrom(parameter.GetType())));
    }

    private void UpdateMethodInfo()
    {
        methodDescriptors.Clear();
        if (Target == null || string.IsNullOrEmpty(MethodName))
        {
            return;
        }
        MethodInfo[] methods = Target.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public);
        foreach (MethodInfo method in methods)
        {
            if (IsMethodValid(method))
            {
                ParameterInfo[] methodParams = method.GetParameters();
                if (AreMethodParamsValid(methodParams))
                {
                    methodDescriptors.Add(new MethodDescriptor(method, methodParams));
                }
            }
        }
        methodDescriptors = methodDescriptors.OrderByDescending(delegate(MethodDescriptor methodDescriptor)
        {
            int num = 0;
            if (methodDescriptor.HasParameters)
            {
                Type type = methodDescriptor.SecondParameterType;
                while (type != typeof(EventArgs))
                {
                    num++;
                    type = type.BaseType;
                }
            }
            return methodDescriptor.ParameterCount + num;
        }).ToList();
    }

    private bool IsMethodValid(MethodInfo method)
    {
        if (!string.Equals(method.Name, MethodName, StringComparison.Ordinal))
        {
            return false;
        }
        if (method.ReturnType != typeof(void))
        {
            return false;
        }
        return true;
    }

    private static bool AreMethodParamsValid(ParameterInfo[] methodParams)
    {
        if (methodParams.Length == 2)
        {
            if (methodParams[0].ParameterType != typeof(object))
            {
                return false;
            }
            if (!typeof(EventArgs).IsAssignableFrom(methodParams[1].ParameterType))
            {
                return false;
            }
        }
        else if (methodParams.Length != 0)
        {
            return false;
        }
        return true;
    }

    private static void OnMethodNameChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
    {
        ((CallMethodAction)sender).UpdateMethodInfo();
    }

    private static void OnTargetObjectChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
    {
        ((CallMethodAction)sender).UpdateMethodInfo();
    }
}

 

posted @ 2024-07-09 11:40  FredGrit  阅读(3)  评论(0编辑  收藏  举报