鼠标绑定鼠标滚轮以放大WPF和MVVM

时间:2010-02-16 07:53:33

标签: wpf data-binding mvvm mouse cinch

好的,我已经找到了如何使用LayoutTransform和ScaleTransform让我的UI元素网格缩放。我不明白的是我如何让我的View响应CTRL + MouseWheelUp \ Down来做到这一点,以及如何使代码适应MVVM模式。

我的第一个想法是将ZoomFactor存储为属性,并绑定到命令进行调整。

我正在寻找类似的东西:

<UserControl.InputBindings>
 <MouseBinding Command="{Binding ZoomGrid}" Gesture="Control+WheelClick"/>
</UserControl.InputBindings>

但我看到了两个问题:

1)我认为没有办法判断方向盘是向上还是向下移动,也无法确定如何确定方向量。我见过MouseWheelEventArgs.Delta,但不知道怎么弄它。

2)绑定到viewmodel上的命令似乎不对,因为它严格来说是View事物。

由于缩放仅限于UI视图,我认为实际的代码应该放在代码隐藏中。

你们会如何实现这个?

p.s。,我正在使用Cinch for MVVM .net \ wpf 4.0。

6 个答案:

答案 0 :(得分:10)

真正的答案是编写自己的鼠标手势,这很容易。

<MouseBinding Gesture="{x:Static me:MouseWheelGesture.CtrlDown}"  
              Command="me:MainVM.SendBackwardCommand" />

public class MouseWheelGesture : MouseGesture
{
    public static MouseWheelGesture CtrlDown
        => new MouseWheelGesture(ModifierKeys.Control) { Direction = WheelDirection.Down


    public MouseWheelGesture(): base(MouseAction.WheelClick)
    {
    }

    public MouseWheelGesture(ModifierKeys modifiers) : base(MouseAction.WheelClick, modifiers)
    {
    }

    public WheelDirection Direction { get; set; }

    public override bool Matches(object targetElement, InputEventArgs inputEventArgs)
    {
        if (!base.Matches(targetElement, inputEventArgs)) return false;
        if (!(inputEventArgs is MouseWheelEventArgs args)) return false;
        switch (Direction)
        {
            case WheelDirection.None:
                return args.Delta == 0;
            case WheelDirection.Up:
               return args.Delta > 0;
            case WheelDirection.Down:
                return args.Delta < 0;
            default:
                return false;
        }
    }



    public enum WheelDirection
    {
      None,
      Up,
      Down,
    }

}

答案 1 :(得分:4)

我建议您在VM中实现通用缩放命令。该命令可以使用新的缩放级别进行参数化,或者(甚至更简单)可以实现 IncreaseZoomCommand DecreaseZoomCommand 。然后使用视图的代码在处理鼠标滚轮事件的事件参数后调用这些命令。如果增量为正,则放大,如果为负缩小。

通过使用几行代码解决这个问题没有任何害处。 MVVM的主要思想是,您可以在不依赖于UI的对象中跟踪和修改几乎完整的视图状态(增强可测试性)。因此,作为缩放结果的新视口的计算应该在VM中完成,而不是在后面的代码中完成。

后面代码中存在的可测试性的小差距可以被自动UI测试忽略或覆盖。但是,自动UI测试可能非常昂贵。

答案 2 :(得分:1)

如果您不想使用后面的代码,可以使用mvvm light的EventToCommand功能:

查看:

 <...
     xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WPF4"
 xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 
     ...> 
<i:Interaction.Triggers>
         <i:EventTrigger EventName="PreviewMouseWheel">
             <cmd:EventToCommand Command="{Binding
     Path=DataContext.ZoomCommand,
     ElementName=Root, Mode=OneWay}"
         PassEventArgsToCommand="True"   />
         </i:EventTrigger> </i:Interaction.Triggers>

视图模型:

ZoomCommand = new RelayCommand<RoutedEventArgs>(Zoom);
...
public void Zoom(RoutedEventArgs e)
{
    var originalEventArgs = e as MouseWheelEventArgs;
    // originalEventArgs.Delta contains the relevant value
}

我希望这有助于某人。我知道这个问题有点老......

答案 3 :(得分:0)

我认为您尝试做的事情与视图非常相关,因此将代码置于代码后面(至少在我看来)没有任何害处,尽管我确信有优雅的方法来处理这样的问题。它更基于viewmodel。

您应该能够注册到OnPrevewMouseWheel事件,检查用户是否按下了控制键并相应地更改缩放系数以获得您正在寻找的缩放效果。

答案 4 :(得分:0)

我同意这两个答案,并且只会补充说,在这种情况下使用代码是唯一的方法,所以你甚至不必考虑它是否违反任何良好做法。

事实上,获取MouseEventArgs(以及Delta)的唯一方法是在代码背后,所以抓住你需要的东西(不需要逻辑)并将其作为olli传递给你的视图模型建议。

另一方面,您可能希望使用更通用的增量(例如,在将其作为步骤传递给视图模型之前将其除以120),以使其不知道与视图或操作系统相关的任何约定。这将允许在视图模型中最大程度地重用代码。

答案 5 :(得分:0)

为了避免整个问题,还有一个选择: - 在xaml中使用ContentPresenter并将其内容绑定到viewmodel对象。 - 在viewmodel中处理mousewheel事件。