Вопрос

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

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

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

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

но я вижу 2 проблемы:

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

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

Поскольку масштабирование предназначено исключительно для просмотра пользовательского интерфейса, я думаю, что фактический код должен находиться в коде программной части.

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

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

Это было полезно?

Решение

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

Нет ничего плохого в том, чтобы решить эту проблему, используя несколько строк кода.Основная идея 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,
    }

}

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

Модель просмотра:

ZoomCommand = new RelayCommand<RoutedEventArgs>(Zoom);
...
public void Zoom(RoutedEventArgs e)
{
    var originalEventArgs = e as MouseWheelEventArgs;
    // originalEventArgs.Delta contains the relevant value
}

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top