【问题标题】:WPF Zoom Canvas Center on Mouse Position鼠标位置上的 WPF 缩放画布中心
【发布时间】:2018-03-07 12:59:28
【问题描述】:
<utils:ScrollViewer x:Name="ImageViewer" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" Grid.Row="2"                                                                   
                                       CurrentHorizontalOffset="{Binding ScrollHorizontalValue, Mode=TwoWay}"
                                       CurrentVerticalOffset="{Binding ScrollVerticalValue, Mode=TwoWay}"                                        
                                       >
                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="PreviewMouseWheel">
                            <cmd:EventToCommand Command="{Binding MouseWheelZoomCommand}" PassEventArgsToCommand="True"/>
                        </i:EventTrigger>
                        <i:EventTrigger EventName="ScrollChanged">
                            <cmd:EventToCommand Command="{Binding ScrollChangedCommand}" PassEventArgsToCommand="True"/>
                        </i:EventTrigger>
                    </i:Interaction.Triggers>
                    <Grid Background="{StaticResource ThatchBackground}" RenderTransformOrigin="0.5,0.5">
                        <ItemsControl ItemsSource="{Binding CanvasItems}" ItemTemplate="{StaticResource templateOfROI}">
                            <ItemsControl.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <Canvas x:Name="BackPanel"
                                        Width="{Binding DataContext.ImageWidth, ElementName=MainGrid}" 
                                        Height="{Binding DataContext.ImageHeight, ElementName=MainGrid}"
                                        ClipToBounds="True">
                                        <Canvas.Background>
                                            <ImageBrush x:Name="BackImage"
                                                        ImageSource="{Binding DataContext.SelectedImage.Path, ElementName=MainGrid}"/>
                                        </Canvas.Background>

                                        <i:Interaction.Triggers>
                                            <i:EventTrigger EventName="MouseRightButtonDown">
                                                <cmd:EventToCommand Command="{Binding DataContext.MouseRightCommand, ElementName=MainGrid}"/>
                                            </i:EventTrigger>
                                            <i:EventTrigger EventName="MouseLeftButtonDown">
                                                <cmd:EventToCommand Command="{Binding DataContext.MouseMoveStartCommand, ElementName=MainGrid}" PassEventArgsToCommand="True"/>
                                            </i:EventTrigger>
                                            <i:EventTrigger EventName="MouseMove">
                                                <cmd:EventToCommand Command="{Binding DataContext.MouseMovingCommand, ElementName=MainGrid}" PassEventArgsToCommand="True"/>
                                            </i:EventTrigger>
                                            <i:EventTrigger EventName="MouseRightButtonUp">
                                                <cmd:EventToCommand Command="{Binding DataContext.MouseMoveEndCommand, ElementName=MainGrid}"/>
                                            </i:EventTrigger>
                                            <i:EventTrigger EventName="MouseLeave">
                                                <cmd:EventToCommand Command="{Binding DataContext.MouseLeaveCommand, ElementName=MainGrid}"/>
                                            </i:EventTrigger>
                                        </i:Interaction.Triggers>

                                        <Canvas.LayoutTransform>
                                            <TransformGroup>
                                                <ScaleTransform ScaleX="{Binding ScaleX}"
                                                                ScaleY="{Binding ScaleY}">
                                                </ScaleTransform>
                                        </TransformGroup>
                                    </Canvas.LayoutTransform>
                                </Canvas>
                            </ItemsPanelTemplate>
                        </ItemsControl.ItemsPanel>
                    </ItemsControl>
                </Grid>
            </utils:ScrollViewer>

参考点固定为左点和上点以缩放画布。我想放大和缩小鼠标指针。我如何使它成为 MVVM 模式? (不在代码后面)。使用鼠标滚轮,我可以放大画布。我已经使用了 RenderTransformOrigin、CenterX、CenterY,但它不起作用。我认为我采取了错误的方法。请帮帮我..

【问题讨论】:

  • 处理缩放的代码在哪里?即使它没有按预期工作,您仍应将其作为您当前的方法。

标签: c# wpf xaml mvvm mvvm-light


【解决方案1】:

由于您没有提供当前的缩放代码,下面是一个缩放鼠标位置的通用示例:

<Grid x:Name="grid1" Background="White" MouseWheel="Grid_MouseWheel">
    <Grid x:Name="grid2">
        <Grid.RenderTransform>
            <MatrixTransform/>
        </Grid.RenderTransform>
        <Rectangle Width="20" Height="20" Margin="20" VerticalAlignment="Top" HorizontalAlignment="Left" Fill="Green"/>
    </Grid>
</Grid>

使用更新变换矩阵的代码:

private void Grid_MouseWheel(object sender, MouseWheelEventArgs e)
{
    var matTrans = grid2.RenderTransform as MatrixTransform;
    var pos1 = e.GetPosition(grid1);

    var scale = e.Delta > 0 ? 1.1 : 1 / 1.1;

    var mat = matTrans.Matrix;
    mat.ScaleAt(scale, scale, pos1.X, pos1.Y);
    matTrans.Matrix = mat;
    e.Handled = true;
}

【讨论】:

  • 我希望你不介意,但我根据你的代码添加了一个答案,以Behavior 的形式供尝试坚持 MVVM 模式的人使用。
  • @BradleyUffner 我一点也不介意。各种好的解决方案可以帮助整个 SO,我对你提到我的贡献的方式非常满意;)
  • 这是一个非常简单的解决方案。我的问题是,有没有办法改变缩放内容的过滤方式(即使用最近的邻居)?我将它与具有平铺图像背景的画布一起使用,尽管在图像上尝试了RenderOptions.BitmapScalingMode,但它没有任何效果,大概是因为渲染转换是在之后应用的。
  • 嗨@Logix 好问题,但我不知道答案。也许检查 stackoverflow.com/a/2913679/5265292 或与 BitmapScalingMode 专门相关的其他答案之一是否有帮助。否则你可能应该打开一个新问题
【解决方案2】:

我将@Grek40 的代码转换为Behavior,以供任何试图坚持使用MVVM 模式的人使用。如果您对此进行投票,请记住也对他的答案进行投票,因为我的答案是基于他的工作。它需要System.Windows.Interactivity.WPF nuget 包 Behavior 基类的(或其他一些框架)。您可以将此应用于任何UIElement。它会自动为您添加MatrixTransform,因此您不必在 XAML 中执行此操作(它会覆盖任何现有的转换)。

public class ZoomOnMouseWheel : Behavior<FrameworkElement>
{
    public Key? ModifierKey { get; set; } = null;
    public TransformMode TranformMode { get; set; } = TransformMode.Render;

    private Transform _transform;

    protected override void OnAttached()
    {
        if (TranformMode == TransformMode.Render)
        {
            _transform = AssociatedObject.RenderTransform = new MatrixTransform();
        }
        else
        {
            _transform = AssociatedObject.LayoutTransform = new MatrixTransform();
        }

        AssociatedObject.MouseWheel += AssociatedObject_MouseWheel;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.MouseWheel -= AssociatedObject_MouseWheel;
    }

    private void AssociatedObject_MouseWheel(object sender, MouseWheelEventArgs e)
    {
        if ((!ModifierKey.HasValue || !Keyboard.IsKeyDown(ModifierKey.Value)) && ModifierKey.HasValue)
        {
            return;
        }

        if (!(_transform is MatrixTransform transform))
        {
            return;
        }

        var pos1 = e.GetPosition(AssociatedObject);
        var scale = e.Delta > 0 ? 1.1 : 1 / 1.1;
        var mat = transform.Matrix;
        mat.ScaleAt(scale, scale, pos1.X, pos1.Y);
        transform.Matrix = mat;
        e.Handled = true;
    }
}

public enum TransformMode
{
    Layout,
    Render,
}

你可以这样使用它:

<Grid>
    <interactivity:Interaction.Behaviors>
        <behaviors:ZoomOnMouseWheel />
    </interactivity:Interaction.Behaviors>
    <!--Your grid content here-->
</Grid>

别忘了xmlns

xmlns:interactivity="http://schemas.microsoft.com/expression/2010/interactivity"

【讨论】:

  • 我添加了仅在通过ModifierKey 属性按住修改键(例如LeftCtrl)时滚动的功能,以及控制转换是否作为@ 完成的功能987654332@ 或 LayoutTransform 通过 TransformMode 属性。默认为RenderTransform,但如果将带有Behavior的元素放在滚动查看器中,并将其设置为LayoutTransform,则在放大时可以获得滚动条。
猜你喜欢
  • 2014-08-18
  • 2014-04-16
  • 2019-04-07
  • 1970-01-01
  • 2018-08-21
  • 1970-01-01
  • 2018-02-01
  • 2013-03-26
  • 1970-01-01
相关资源
最近更新 更多