WPFとMVVMにズームインし、マウスホイールをMouseBinding
-
20-09-2019 - |
質問
OK、私はLayoutTransformとScaleTransformを使用することによって、ズームするUI要素の私のグリッドを取得する方法を考え出しました。私は理解していないことは、私は私の見解は、それを行うには、Ctrl + MouseWheelUp \下に応えるために得ることができる方法で、どのようにMVVMパターンにコードに合うように。
私の最初のアイデアは、プロパティとしてZoomFactorを保存し、それを調整するためのコマンドにバインドしました。
私のようなものを見ていました
<UserControl.InputBindings>
<MouseBinding Command="{Binding ZoomGrid}" Gesture="Control+WheelClick"/>
</UserControl.InputBindings>
私は2つの問題を参照してください。
1)私は、ホイールが上下に移動されたかどうかを指示する方法があるとは思わない、また私はどのくらいで決定する方法を見ることができます。私はそれを取得する方法をMouseWheelEventArgs.Deltaを見たが、見当がつかないました。
それは厳密に見ることだとして2)のviewmodel上のコマンドに結合すると、右のようではありません。
ズームは厳密であるのでUIビューのみ、私は実際のコードは、コードビハインドに行くべきだと思っています。
あなたたちはこれを実装するだろうか?
p.s。、私はMVVMのためのシンチを使用して4.0 WPF .NET \を使用しています。
解決
私はあなたのVMでの一般的なズームコマンドを実装することをお勧めします。コマンドは、のIncreaseZoomCommand を実装することができ(おそらく単純)新しいズームレベルでパラメータ、またはすることができ、のDecreaseZoomCommand の。そして、あなたはマウスホイールイベントのイベント引数を処理した後に、これらのコマンドを呼び出すことが背景にあるビューのコードを使用します。デルタが正の場合、負のズームアウト場合は、ズームインます。
の後ろに数行のコードを使用してこの問題を解決するには害はありません。 MVVMの主なアイデアは、あなたがUI(テスト容易性を向上さ)に依存しないオブジェクト内のビューのほぼ完全な状態を追跡し、修正することができます、ということです。その結果、ズームの結果であり、新しいビューポートの計算は、VMにしていないの背後にあるコードで行う必要があります。
の後ろにコード内に存在するテスト容易性の小さなギャップのいずれか無視または自動UIテストで覆うことができます。自動UIテストは、しかし、非常に高価になることができます。
他のヒント
本当のanwserは簡単です、あなた自身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,
}
}
あなたはMVVM光の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>
のViewModelます:
ZoomCommand = new RelayCommand<RoutedEventArgs>(Zoom);
...
public void Zoom(RoutedEventArgs e)
{
var originalEventArgs = e as MouseWheelEventArgs;
// originalEventArgs.Delta contains the relevant value
}
私は、これは誰かに役立ちます願っています。私は質問が一種である知っているの古い...
私は(少なくとも私の意見で)の後ろにあなたのコード内のコードを入れても害はありませんので、私はこのようにハンドリングのエレガントな方法があると確信しているが、あなたは、非常に多くのビューに関連してやろうとするものだと思いますそれはより多くのviewmodel基づいています。
あなたは、ユーザーが押されたコントロールキーを持って、あなたが探しているズーム効果を得るために、それに応じてズーム倍率を変更しているかどうかを確認、OnPrevewMouseWheelイベントに登録することができるはずです。
私は両方の答えに同意する、とだけこの場合の唯一の方法であるので、それが何か良い慣行を破るかどうあなたも考える必要はありません背後にあるコードを使用することを追加することになります。
事実である、MouseEventArgs(したがってデルタ)のホールドを取得する唯一の方法は、背後にあるコードであるので、あなたは(何のロジックが、そのために必要ありません)が必要なものをつかむとオッリとしてあなたのビューモデルにそれを渡します提案します。
フリップ側では、ビューやOSに関連する規則の無知、それを維持するために、より汎用的なデルタ(ビューモデルへのステップとしてそれを渡す前に、例えば120で割り)を使用することもできます。これは、ビューモデルにあなたのコードの最大の再利用が可能になります。
全体の問題を回避するには、1つのより多くのオプションがあります: XAMLでのContentPresenterを-use、それはコンテンツがviewmodelのオブジェクトにバインドされてみましょう。 viewmodel内マウスホイールイベントを-handleます。