以编程方式绑定鼠标事件mvvm

本文关键字:事件 mvvm 鼠标 绑定 编程 方式 | 更新日期: 2023-09-27 18:29:36

我有一个dll,它添加/删除Canvases,并处理在它们上的绘制。

我希望"注册"我添加到MouseMoveMouseDownMouseUp事件的每个Canvas

我知道我可以添加这3个事件函数,并以传统的方式进行,但我想知道在MVVM中是否有更优雅的方式来实现这一点?

我试图搜索它,但在使用Interactivityxaml中只找到了它的实现。

以编程方式绑定鼠标事件mvvm

有几种方法可以做到这一点,但根据我的经验,通过创建Blend行为可以节省大量工作。首先声明一个可以用来与视图模型通信的接口,这里有一个非常简单的接口:

public interface IMouseCaptureProxy
{
    event EventHandler Capture;
    event EventHandler Release;
    void OnMouseDown(object sender, MouseCaptureArgs e);
    void OnMouseMove(object sender, MouseCaptureArgs e);
    void OnMouseUp(object sender, MouseCaptureArgs e);
}
public class MouseCaptureArgs
{
    public double X {get; set;}
    public double Y { get; set; }
    public bool LeftButton { get; set; }
    public bool RightButton { get; set; }
}

然后行为本身:

public class MouseCaptureBehavior : Behavior<FrameworkElement>
{
    public static readonly DependencyProperty ProxyProperty = DependencyProperty.RegisterAttached(
        "Proxy",
        typeof(IMouseCaptureProxy),
        typeof(MouseCaptureBehavior),
        new PropertyMetadata(null, OnProxyChanged));
    public static void SetProxy(DependencyObject source, IMouseCaptureProxy value)
    {
        source.SetValue(ProxyProperty, value);
    }
    public static IMouseCaptureProxy GetProxy(DependencyObject source)
    {
        return (IMouseCaptureProxy)source.GetValue(ProxyProperty);
    }
    private static void OnProxyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (e.OldValue is IMouseCaptureProxy)
        {
            (e.OldValue as IMouseCaptureProxy).Capture -= OnCapture;
            (e.OldValue as IMouseCaptureProxy).Release -= OnRelease;
        }
        if (e.NewValue is IMouseCaptureProxy)
        {
            (e.NewValue as IMouseCaptureProxy).Capture += OnCapture;
            (e.NewValue as IMouseCaptureProxy).Release += OnRelease;
        }
    }
    static void OnCapture(object sender, EventArgs e)
    {
        var behavior = sender as MouseCaptureBehavior;
        if (behavior != null)
            behavior.AssociatedObject.CaptureMouse();
    }
    static void OnRelease(object sender, EventArgs e)
    {
        var behavior = sender as MouseCaptureBehavior;
        if (behavior != null)
            behavior.AssociatedObject.ReleaseMouseCapture();
    }
    protected override void OnAttached()
    {
        base.OnAttached();
        this.AssociatedObject.PreviewMouseDown += OnMouseDown;
        this.AssociatedObject.PreviewMouseMove += OnMouseMove;
        this.AssociatedObject.PreviewMouseUp += OnMouseUp;
    }
    protected override void OnDetaching()
    {
        base.OnDetaching();
        this.AssociatedObject.PreviewMouseDown -= OnMouseDown;
        this.AssociatedObject.PreviewMouseMove -= OnMouseMove;
        this.AssociatedObject.PreviewMouseUp -= OnMouseUp;
    }
    private void OnMouseDown(object sender, MouseButtonEventArgs e)
    {
        var proxy = GetProxy(this);
        if (proxy != null)
        {
            var pos = e.GetPosition(this.AssociatedObject);
            var args = new MouseCaptureArgs {
                X = pos.X,
                Y = pos.Y,
                LeftButton = (e.LeftButton == MouseButtonState.Pressed),
                RightButton = (e.RightButton == MouseButtonState.Pressed)
            };
            proxy.OnMouseDown(this, args);
        }
    }
    private void OnMouseMove(object sender, MouseEventArgs e)
    {
        var proxy = GetProxy(this);
        if (proxy != null)
        {
            var pos = e.GetPosition(this.AssociatedObject);
            var args = new MouseCaptureArgs {
                X = pos.X,
                Y = pos.Y,
                LeftButton = (e.LeftButton == MouseButtonState.Pressed),
                RightButton = (e.RightButton == MouseButtonState.Pressed)
            };
            proxy.OnMouseMove(this, args);
        }
    }
    private void OnMouseUp(object sender, MouseButtonEventArgs e)
    {
        var proxy = GetProxy(this);
        if (proxy != null)
        {
            var pos = e.GetPosition(this.AssociatedObject);
            var args = new MouseCaptureArgs
            {
                X = pos.X,
                Y = pos.Y,
                LeftButton = (e.LeftButton == MouseButtonState.Pressed),
                RightButton = (e.RightButton == MouseButtonState.Pressed)
            };
            proxy.OnMouseUp(this, args);
        }
    }
}

然后你只需将其添加到你想要鼠标事件通知的任何控件:

                    <Canvas>
                        <i:Interaction.Behaviors>
                            <behaviors:MouseCaptureBehavior Proxy="{Binding}" />
                        </i:Interaction.Behaviors>

在这种情况下,我将Proxy绑定到DataContext,而DataContext恰好是MainViewModel,因此请确保MainViewModel继承IMouseCaptureProxy。然后,实现各种处理程序和捕获/释放处理程序就很简单了,如果需要的话,您可以使用它们来捕获和释放鼠标:

    public event EventHandler Capture;
    public event EventHandler Release;
    public void OnMouseDownobject sender, MouseCaptureArgs e)
    {
        this.Capture(sender, null);
        // etc
    }

有些人会争辩说,从技术上讲,将sender传递到处理程序是对MVVM的违反,我个人认为我可能同意这一点,但这至少应该足以让你开始。如果你是一个MVVM纯粹主义者,那么你会想修改行为,而不是创建在内部跟踪这类事情的中间对象。