鼠标位置上的 WPF 缩放画布中心
Posted
技术标签:
【中文标题】鼠标位置上的 WPF 缩放画布中心【英文标题】:WPF Zoom Canvas Center on Mouse Position 【发布时间】: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,但它不起作用。我认为我采取了错误的方法。请帮帮我..
【问题讨论】:
处理缩放的代码在哪里?即使它没有按预期工作,您仍应将其作为您当前的方法。 【参考方案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 好问题,但我不知道答案。也许检查 ***.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
,则在放大时可以获得滚动条。以上是关于鼠标位置上的 WPF 缩放画布中心的主要内容,如果未能解决你的问题,请参考以下文章