【问题标题】:MouseBinding the mousewheel to zoom in WPF and MVVM鼠标绑定鼠标滚轮以放大 WPF 和 MVVM
【发布时间】:2010-02-16 07:53:32
【问题描述】:

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

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

我在看类似的东西:

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

但我发现了 2 个问题:

1)我认为没有办法判断轮子是向上还是向下移动,我也看不出如何确定多少。我见过 MouseWheelEventArgs.Delta,但不知道如何获得它。

2) 绑定到视图模型上的命令似乎不正确,因为它严格来说是一个视图。

由于缩放严格来说只是 UI 视图,我认为实际代码应该放在代码隐藏中。

你们将如何实现这一点?

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

【问题讨论】:

标签: wpf data-binding mvvm mouse cinch


【解决方案1】:

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

<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,
    }
}

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      【解决方案3】:

      如果不想使用后面的代码,可以使用 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
      }
      

      我希望这对某人有所帮助。我知道这个问题有点老了......

      【讨论】:

      • 我觉得奇怪的是你的虚拟机会有一个路由事件
      【解决方案4】:

      我认为您尝试做的事情与视图非常相关,因此将代码放在您的代码后面没有害处(至少在我看来),尽管我确信有一些优雅的方式来处理这种情况它更基于视图模型。

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

      【讨论】:

        【解决方案5】:

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

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

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

        【讨论】:

          【解决方案6】:

          为了避免整个问题,还有一种选择: - 在 xaml 中使用 ContentPresenter 并将其内容绑定到 viewmodel 对象。 - 处理视图模型中的鼠标滚轮事件。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-04-16
            • 1970-01-01
            • 2013-08-29
            • 1970-01-01
            • 2013-10-07
            • 2011-09-29
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多