MouseBinding колесо мыши для увеличения WPF и MVVM - PullRequest
8 голосов
/ 16 февраля 2010

ОК, я выяснил, как увеличить масштаб элементов Grid of UI, используя LayoutTransform и ScaleTransform. Чего я не понимаю, так это как заставить мой View реагировать на CTRL + MouseWheelUp \ Down, чтобы сделать это, и как вписать код в шаблон MVVM.

Моей первой идеей было сохранить ZoomFactor как свойство и связать его с командой для его настройки.

Я смотрел на что-то вроде:

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

но я вижу 2 вопроса:

1) Я не думаю, что есть способ определить, было ли колесо перемещено вверх или вниз, и я не вижу, как определить, насколько. Я видел MouseWheelEventArgs.Delta, но не знаю, как его получить.

2) Привязка к команде на модели представления кажется неправильной, поскольку это строго элемент View.

Так как масштабирование строго UI View, я думаю, что реальный код должен идти в коде позади.

Как вы, ребята, это реализовали?

p.s., Я использую .net \ wpf 4.0, используя Cinch для MVVM.

Ответы [ 6 ]

10 голосов
/ 23 сентября 2011

Настоящий ответ - написать свой собственный 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,
    }

}
4 голосов
/ 16 февраля 2010

Я бы посоветовал вам реализовать универсальную команду масштабирования в вашей виртуальной машине. Команда может быть параметризована с новым уровнем масштабирования или (возможно, даже проще) вы можете реализовать IncreaseZoomCommand и DecreaseZoomCommand . Затем используйте код представления для вызова этих команд после обработки аргументов события колесика мыши. Если дельта положительна, увеличьте, если отрицательный уменьшите.

Нет никакого вреда в решении этой проблемы с использованием нескольких строк кода. Основная идея MVVM заключается в том, что вы можете отслеживать и изменять практически полное состояние вашего представления в объекте, который не зависит от пользовательского интерфейса (улучшает тестируемость). Следовательно, вычисление нового окна просмотра, являющегося результатом масштабирования, должно выполняться в виртуальной машине, а не в коде позади.

Небольшой пробел в тестируемости, который существует в коде, можно игнорировать или покрывать автоматическими тестами пользовательского интерфейса. Однако автоматические тесты пользовательского интерфейса могут быть очень дорогими.

1 голос
/ 26 июня 2011

Если вы не хотите использовать код позади, вы можете использовать функциональность 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
}

Надеюсь, это кому-нибудь поможет. Я знаю, что вопрос довольно старый ...

0 голосов
/ 19 декабря 2013

Чтобы избежать всей проблемы, есть еще один вариант: -используйте ContentPresenter в xaml и пусть его содержимое будет привязано к объекту модели представления. - обрабатывать события колесика мыши внутри модели представления.

0 голосов
/ 19 марта 2010

Я согласен с обоими ответами и только добавил бы, что использование кода позади - единственный способ в этом случае, так что вам даже не нужно думать о том, нарушает ли он какие-либо хорошие практики или нет.

Факт в том, что единственный способ получить MouseEventArgs (и, следовательно, Delta) находится в коде позади, поэтому возьмите то, что вам нужно там (никакой логики для этого не требуется) и передайте его своей модели представления как olli. предлагается.

С другой стороны, вы можете захотеть использовать более общую дельту (например, разделить ее на 120, прежде чем передать ее в качестве шага модели представления), чтобы она не знала каких-либо соглашений, связанных с представлением или ОС. , Это позволит максимально использовать ваш код в модели представления.

0 голосов
/ 16 февраля 2010

Я думаю, что ваши попытки очень сильно связаны с представлением, поэтому нет ничего плохого в том, чтобы поместить код в ваш код (по крайней мере, на мой взгляд), хотя я уверен, что есть элегантные способы обработки этого что это больше основано на модели представления.

Вы должны иметь возможность зарегистрироваться в событии OnPrevewMouseWheel, проверить, нажала ли пользователь управляющую клавишу, и соответственно изменить коэффициент масштабирования, чтобы получить эффект масштабирования, который вы ищете.

...