簡體   English   中英

鼠標綁定鼠標滾輪以放大 WPF 和 MVVM

[英]MouseBinding the mousewheel to zoom in WPF and MVVM

好的,我已經找到了如何通過使用 LayoutTransform 和 ScaleTransform 來縮放 UI 元素網格。 我不明白的是如何讓我的視圖響應 CTRL+MouseWheelUp\\Down 來執行它,以及如何使代碼適合 MVVM 模式。

我的第一個想法是將 ZoomFactor 存儲為一個屬性,並綁定到一個命令來調整它。

我在看類似的東西:

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

但我看到兩個問題:

1)我認為沒有辦法判斷車輪是向上還是向下移動,我也看不到如何確定多少。 我見過 MouseWheelEventArgs.Delta,但不知道如何獲得它。

2) 綁定到視圖模型上的命令似乎不正確,因為它嚴格來說是視圖的事情。

由於縮放只是嚴格的 UI 視圖,我認為實際的代碼應該放在代碼隱藏中。

你們將如何實現這一點?

ps,我正在使用 .net\\wpf 4.0,將 Cinch 用於 MVVM。

真正的答案是編寫自己的 MouseGesture,這很容易。

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

我建議您在 VM 中實現通用縮放命令。 該命令可以使用新的縮放級別進行參數化,或者(也許更簡單)您可以實現increaseZoomCommandDecreaseZoomCommand 然后在處理完鼠標滾輪事件的事件參數后,使用視圖的代碼來調用這些命令。 如果增量為正,則放大,如果為負則縮小。

后面用幾行代碼解決這個問題沒有什么壞處。 MVVM 的主要思想是,您可以在不依賴於 UI(增強可測試性)的對象中跟蹤和修改視圖的幾乎完整狀態。 因此,作為縮放結果的新視口的計算應該在 VM 中完成,而不是在后面的代碼中完成。

代碼背后存在的可測試性的小差距可以被自動 UI 測試忽略或覆蓋。 然而,自動 UI 測試可能非常昂貴。

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

我希望這可以幫助別人。 我知道這個問題有點老了......

為了避免整個問題,還有一個選項:-在 xaml 中使用 ContentPresenter 並將其內容綁定到視圖模型對象。 - 處理視圖模型中的鼠標滾輪事件。

我認為您嘗試做的事情與視圖有很大關系,因此將代碼放在后面的代碼中沒有害處(至少在我看來),盡管我確信有一些優雅的方法可以處理這個問題更多基於視圖模型。

您應該能夠注冊 OnPrevewMouseWheel 事件,檢查用戶是否按下了控制鍵並相應地更改縮放系數以獲得您正在尋找的縮放效果。

我同意這兩個答案,並且只會補充一點,在這種情況下使用代碼隱藏是唯一的方法,因此您甚至不必考慮它是否違反了任何良好做法。

事實是,獲取 MouseEventArgs(以及 Delta)的唯一方法是在后面的代碼中,所以在那里獲取你需要的東西(不需要邏輯)並按照 olli 的建議將它傳遞給你的視圖模型。

另一方面,您可能希望使用更通用的增量(例如,在將其作為步驟傳遞給視圖模型之前將其除以 120),以使其不了解與視圖或操作系統相關的任何約定。 這將允許在視圖模型中最大限度地重用您的代碼。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM