Привязка мыши к колесу мыши для увеличения WPF и MVVM
хорошо, я понял, как получить мою сетку элементов пользовательского интерфейса для увеличения, используя LayoutTransform и ScaleTransform. Я не понимаю, как я могу заставить свое представление реагировать на CTRL+MouseWheelUpDown, чтобы сделать это, и как вписать код в шаблон MVVM.
моей первой идеей было сохранить ZoomFactor как свойство и привязаться к команде для его настройки.
Я смотрел на что-то вроде:
<UserControl.InputBindings>
<MouseBinding Command="{Binding ZoomGrid}" Gesture="Control+WheelClick"/>
</UserControl.InputBindings>
но я вижу 2 проблемы:
1) I не думайте, что есть способ определить, было ли колесо перемещено вверх или вниз, и я не вижу, как определить, насколько. Я видел MouseWheelEventArgs.Дельта, но понятия не имею, как ее достать.
2) привязка к команде на viewmodel не кажется правильной, так как это строго видовая вещь.
Так как масштабирование строго UI View только, я думаю,что фактический код должен идти в коде позади.
как бы вы это реализовали?
p.s., Я ... использование .netwpf 4.0 с помощью Cinch для MVVM.
6 ответов
Я бы предложил вам реализовать общую команду масштабирования в вашей виртуальной машине. Команда может быть параметризована с новым уровнем масштабирования или (возможно, даже проще) вы можете реализовать IncreaseZoomCommand и DecreaseZoomCommand. Затем используйте код представления, чтобы вызвать эти команды после обработки аргументов события колеса мыши. Если дельта положительная, увеличьте, если отрицательная-уменьшите.
нет никакого вреда в решении этой проблема с использованием нескольких строк кода позади. Основная идея MVVM заключается в том, что вы можете отслеживать и изменять почти полное состояние вашего представления в объекте, который не зависит от пользовательского интерфейса (повышает тестируемость). Следовательно, вычисление нового окна просмотра, которое является результатом масштабирования, должно выполняться в виртуальной машине, а не в коде позади.
небольшой разрыв тестируемости, который существует в коде позади, может быть проигнорирован или покрыт автоматическими тестами UI. Однако автоматические тесты UI могут быть очень дорогими.
реальный anwser должен написать свой собственный MouseGesture, что легко.
<MouseBinding Gesture="{x:Static me:MouseWheelGesture.CtrlDown}"
Command="me:MainVM.SendBackwardCommand" />
public class MouseWheelGesture : MouseGesture
{
public WheelDirection Direction { get; set; }
public static MouseWheelGesture CtrlDown
{
get
{
return new MouseWheelGesture(ModifierKeys.Control) { Direction = WheelDirection.Down };
}
}
public MouseWheelGesture(): base(MouseAction.WheelClick)
{
}
public MouseWheelGesture(ModifierKeys modifiers) : base(MouseAction.WheelClick, modifiers)
{
}
public override bool Matches(object targetElement, InputEventArgs inputEventArgs)
{
if (!base.Matches(targetElement, inputEventArgs)) return false;
if (!(inputEventArgs is MouseWheelEventArgs)) return false;
var args = (MouseWheelEventArgs)inputEventArgs;
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,
}
}
Если вы не хотите использовать код, вы можете использовать функциональность EventToCommand MVVM light:
вид:
<...
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 (и, следовательно, Дельта) находится в коде позади, поэтому возьмите то, что вам нужно (для этого не нужна логика), и передайте его своей модели представления, как предложил Олли.
с другой стороны, вы можете использовать более общую дельту (например , разделите его на 120, прежде чем передавать его как шаг к модели представления), чтобы держать его в неведении о любых соглашениях, связанных с представлением или ОС. Это позволит максимально использовать код в модели представления.
чтобы избежать всей проблемы, есть еще один вариант : - используйте ContentPresenter в xaml и пусть его содержимое будет привязано к объекту viewmodel. - обработка событий mousewheel в viewmodel.