Pergunta

Ok, eu descobri como obter minha grade de elementos da interface do usuário para zoom, usando o layoutTransform e o scaletransform. O que não entendo é como posso fazer com que minha visão responda ao Ctrl+Mousewheelup Down para fazê -lo e como ajustar o código no padrão MVVM.

Minha primeira idéia foi armazenar o ZoomFactor como uma propriedade e ligar a um comando para ajustá -lo.

Eu estava olhando para algo como:

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

Mas eu vejo 2 questões:

1) Acho que não há uma maneira de saber se a roda foi movida para cima ou para baixo, nem posso ver como determinar quanto. Eu vi o mousewheeleventargs.delta, mas não tenho idéia de como obtê -lo.

2) A ligação a um comando no ViewModel não parece correta, pois é estritamente uma coisa de visão.

Como o zoom é estritamente visualizado na interface do usuário, estou pensando que o código real deve ir no código-behind.

Como vocês implementariam isso?

PS, estou usando .NET WPF 4.0 usando o Cinch para MVVM.

Foi útil?

Solução

Eu sugeriria que você implemente um comando genérico de zoom na sua VM. O comando pode ser parametrizado com um novo nível de zoom, ou (talvez ainda mais simples), você pode implementar um Aumento do Companhro e DimproaseZoomCommand. Em seguida, use o código da exibição para trás para chamar esses comandos depois de processar os argumentos do evento do evento da roda do mouse. Se o Delta for positivo, amplie, se o zoom negativo aumenta.

Não há mal em resolver esse problema usando algumas linhas de código atrás. A principal idéia do MVVM é que você pode rastrear e modificar quase o estado completo da sua visão em um objeto que não depende da interface do usuário (aprimora a testabilidade). Em conseqüência, o cálculo da nova viewport, que é o resultado do zoom, deve ser feita na VM e não no código por trás.

A pequena lacuna de testabilidade que existe no código por trás pode ser desconsiderada ou coberta por testes automáticos da interface do usuário. Os testes automáticos da interface do usuário, no entanto, podem ser muito caros.

Outras dicas

O verdadeiro Anwser é escrever seu próprio Mousegesture, o que é fácil.

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

}

Se você não quiser usar o código atrás, você pode usar a funcionalidade EventToCommand do MVVM Light:

Visão:

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

Espero que isso ajude alguém. Eu sei que a pergunta é meio velha ...

Eu acho que o que você está tentando fazer está muito relacionado à visão, para que não haja mal em colocar o código em seu código para trás (pelo menos na minha opinião), embora eu tenha certeza de que existem maneiras elegantes de lidar com isso de modo que seja Mais baseado em ViewModel.

Você poderá se registrar no evento OnPrevewMouse Wheel, verifique se o usuário pressionou a tecla de controle e altere seu fator de zoom de acordo para obter o efeito de zoom que você está procurando.

Eu concordo com as duas respostas e apenas acrescentaria que usar o código por trás é a única maneira neste caso, para que você nem precise pensar se isso quebrar boas práticas ou não.

O fato é que a única maneira de se apossar dos MouseeventArgs (e, portanto, o delta) está no código por trás, então pegue o que você precisa lá (nenhuma lógica necessária para isso) e transmita -o ao seu modelo de exibição, como Olli sugeriu.

Por outro lado, você pode usar um delta mais genérico (por exemplo, divida -o por 120 antes de passá -lo como uma etapa para o modelo de visualização) para mantê -lo ignorante de quaisquer convenções relacionadas à visualização ou ao sistema operacional. Isso permitirá a reutilização máxima do seu código no modelo de visualização.

Para evitar todo o problema, há mais uma opção: -Use um conteúdo do Teal no XAML e deixe que seu conteúdo esteja ligado a um objeto ViewModel. -Mear os eventos da roda do mouse dentro do viewmodel.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top