当前位置: 首页 > 知识库问答 >
问题:

在Wpf中使用ScrollView和ViewBox缩放鼠标点

齐奕
2023-03-14

我有一些路径绘制到WPF中的屏幕。使用的坐标非常小,所以它们被制作成用一个视图框填充屏幕。我现在正在尝试实现平移和缩放功能。我希望能够缩放到鼠标与ui相关的任何地方(即缩放的屏幕中心等于鼠标坐标)。当前的结果是,缩放时屏幕的中心不能反映UI上鼠标的准确位置。

<Grid Name="MasterGrid" DataContext="{StaticResource mainWindowViewModel}">

    <ScrollViewer HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible" Name="VisualisationScroller">
        <Viewbox Name="VisualisationBox" Stretch="Fill" Loaded="VisualisationBox_Loaded">

            <ItemsControl Name="CustomDrawingElement" ItemsSource="{Binding Trajectories}" Width="{Binding VisualisationWidth}" Height="{Binding VisualisationHeight}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate DataType="data:VisualisedTrajectory">
                        <Path Data = "{Binding PathData}" Stroke="Red" StrokeThickness="0.001" Fill="Transparent" />
                    </DataTemplate>
                </ItemsControl.ItemTemplate>

                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Canvas
                            Background="DarkGray"
                            IsItemsHost="True">
                        </Canvas>

                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>

                <ItemsControl.RenderTransform>

                    <TransformGroup>
                        <ScaleTransform ScaleX="1" ScaleY="1" />
                        <TranslateTransform />
                    </TransformGroup>

                </ItemsControl.RenderTransform>

            </ItemsControl>

        </Viewbox>
    </ScrollViewer>
</Grid>

视图模型

public class MainWindowViewModel : BaseViewModel
{

    public MainWindowViewModel()
    {
        VisualiseRawTrajectories();

    }

    private ObservableCollection<VisualisedTrajectory> _trajectories = new ObservableCollection<VisualisedTrajectory>();
    public ObservableCollection<VisualisedTrajectory> Trajectories
    {
        get { return _trajectories; } 
    }

    #region VisualisationDimensions

    private double _visualisationWidth = 100;
    public double VisualisationWidth
    {
        get { return _visualisationWidth; }
        private set { _visualisationWidth = value; }
    }

    private double _visualisationHeight = 100;
    public double VisualisationHeight
    {
        get { return _visualisationHeight; }
        private set { _visualisationHeight = value; }
    }

    #endregion

    public void VisualiseRawTrajectories()
    {
        var rand = new Random();

        for (int i = 0; i < 5; i++)
        {
            var currentTrajectorySet = new List<Point>(); //each time through reinitialise
            for (int j = 0; j < 5; j++)
            {
                currentTrajectorySet.Add(new Point(rand.NextDouble() * 0.5, rand.NextDouble() * 0.5)); //add a new point with max 0.5
                if(j == 4)
                {
                    currentTrajectorySet.Add(new Point(0.5, 0.5)); //for good measure :)
                    _trajectories.Add(new VisualisedTrajectory(CreatePathData(currentTrajectorySet)));
                }
            }
        }

        VisualisationHeight = 0.5;
        VisualisationWidth = 0.5; //just for demonstration purposes
        OnPropertyChanged("VisualisationHeight");
        OnPropertyChanged("VisualisationWidth");

    }

    private Geometry CreatePathData(IList<Point> points)
    {
        var geometry = new StreamGeometry {FillRule = FillRule.EvenOdd};
        using (StreamGeometryContext ctx = geometry.Open())
        {
            ctx.BeginFigure(points[0], false, false); //use the first index
            ctx.PolyLineTo(points, true, true);
        }
        return (Geometry)geometry.GetAsFrozen(); 
    }

}

查看后面的代码

public MainWindow()
    {
        InitializeComponent();
        VisualisationScroller.PreviewMouseWheel += OnPreviewMouseWheel;
    }

    private Point originalDimensions;
    private void VisualisationBox_Loaded(object sender, RoutedEventArgs e)
    {
        Viewbox viewBox = sender as Viewbox;
        viewBox.Width = viewBox.ActualWidth;
        viewBox.Height = viewBox.ActualHeight;
        originalDimensions = new Point(viewBox.ActualWidth, viewBox.ActualHeight);

    }


    #region Zoom

    private int _numberDrawnItems = 0;
    private void OnPreviewMouseWheel(object sender, MouseWheelEventArgs e)
    {
        var zoomScale = new Point(CustomDrawingElement.RenderTransform.Value.M11,
                                  CustomDrawingElement.RenderTransform.Value.M22); //gets the scale x and scale y


        if (CustomDrawingElement != null && _numberDrawnItems != CustomDrawingElement.Items.Count) //if there was something draw to screen
        {
            _numberDrawnItems = CustomDrawingElement.Items.Count;
            CustomDrawingElement.RenderTransformOrigin = new Point(0.5, 0.5); //if not set zoom from center
        }
        if (e.Delta > 0)
        {
            if (CustomDrawingElement != null)
            {

                VisualisationBox.Width = originalDimensions.X * (zoomScale.X + 1);
                VisualisationBox.Height = originalDimensions.Y * (zoomScale.Y + 1);


                var mousePosition = e.GetPosition(MasterGrid);
                CustomDrawingElement.RenderTransformOrigin = new Point(mousePosition.X / MasterGrid.ActualWidth, mousePosition.Y / MasterGrid.ActualHeight);
                CustomDrawingElement.RenderTransform = new MatrixTransform(zoomScale.X + 1, 0, 0, zoomScale.Y + 1, 0, 0);


            }
        }
        if (e.Delta < 0)
        {
            if (zoomScale.X > 1 && zoomScale.Y > 1) //stops you from zooming out too much
            {
                if (CustomDrawingElement != null)
                {

                    VisualisationBox.Width = VisualisationBox.Width - originalDimensions.X;
                    VisualisationBox.Height = VisualisationBox.Height - originalDimensions.Y;

                    CustomDrawingElement.RenderTransform = new MatrixTransform(zoomScale.X - 1, 0, 0, zoomScale.Y - 1, 0, 0);


                }
            }
        }

        e.Handled = true;
    }

    #endregion //Zooming code


}

共有1个答案

罗智刚
2023-03-14

解决了它将缩放视图的后退代码更改为:

if (e.Delta > 0)
        {
            if (CustomDrawingElement != null)
            {
                //zoom

                _zoomScale++; //increase it now that we have zoomed
                VisualisationBox.Width = _originalDimensions.X * (_zoomScale);
                VisualisationBox.Height = _originalDimensions.Y * (_zoomScale);

                ScrollerDimensions.Content = VisualisationScroller.ActualWidth + "x" + VisualisationScroller.ActualHeight;
                BoxDimensions.Content = VisualisationBox.ActualWidth + "x" + VisualisationBox.ActualHeight;

                var mousePosition = e.GetPosition(MasterGrid);
                mousePosition = MasterGrid.TransformToVisual(VisualisationBox).Transform(mousePosition);

                ScrolledPoint.Content = mousePosition.X + "," + mousePosition.Y;
                VisualisationScroller.ScrollToHorizontalOffset(mousePosition.X);
                VisualisationScroller.ScrollToVerticalOffset(mousePosition.Y);

            }
        }
        if (e.Delta < 0)
        {
            if (_zoomScale > 1) //stops you from zooming out too much
            {
                if (CustomDrawingElement != null)
                {
                    var mousePosition = e.GetPosition(MasterGrid);

                    _zoomScale -= 1; //decrease the zoom
                    VisualisationBox.Width = VisualisationBox.Width - _originalDimensions.X;
                    VisualisationBox.Height = VisualisationBox.Height - _originalDimensions.Y;
                    mousePosition = MasterGrid.TransformToVisual(VisualisationBox).Transform(mousePosition);
                    mousePosition = new Point(mousePosition.X - _originalDimensions.X, mousePosition.Y - _originalDimensions.Y);

                    VisualisationScroller.ScrollToHorizontalOffset(mousePosition.X);
                    VisualisationScroller.ScrollToVerticalOffset(mousePosition.Y);
                }
            }
        }

        e.Handled = true;

如果有人感兴趣,这里是完成的解决方案文件与平移实现了。

 类似资料:
  • 我正在尝试将鼠标点击坐标转换为画布坐标。画布可以动态缩放。我实现了缩放功能,缩放转换整个画布。画布本身有一个图像作为窗口的背景。当用户使用鼠标滚轮时,背景会放大和缩小。如何转换鼠标点击坐标以反映图像上的缩放位置? 缩放地图图像代码: 将图标添加到地图图像: 我基本上是想用鼠标左键在地图上添加一个新的图标图像。但是,如果在我尝试添加图标时放大了地图,则图像的位置与单击的地图位置不相关。它会转到离鼠标

  • 我有一个自定义图表,我使用以下代码缩放它: 我注意到当我用鼠标滚轮滚动图表时,我不能缩放鼠标指向的图表。相反,图表会向左或向右缩放。

  • 问题内容: 这里是我想要的描述:在tkinter画布中绘制几何对象(在此为矩形)的集合,然后蜜蜂通过鼠标探索该画布。单击并拖动以移动画布,滚动放大和缩小。 使用本主题,我找到了单击和拖动部分:使用Mousewith-mouse 移动tkinter画布 我设法写了一些滚动缩放。移动和缩放都可以很好地分开工作。 问题 :如果移动然后放大,则变焦的焦点不再是光标所在的位置。 有什么建议吗? 这是一段要测

  • 我正在研究一个svg平面布局,用户应该可以放大和缩小。 当我第一次编码它时,缩放特性起作用,但是svg不响应容器大小。我添加了viewbox属性以使其具有响应性,但这会干扰缩放功能--即使您尝试缩放,它也会缩放,并且缩放不像添加viewbox之前那样工作。 以下是两个相互依存关系来演示此问题: 没有ViewBox-SVG可以正确缩放,但不响应容器大小 https://codepen.io/nico

  • 在过去的几天里,我一直在开发C Mandelbrot集合程序,我设法让它工作得很好,然而,我的最终目标是能够用我的鼠标平稳地放大集合,这是我还没有做到的,所以我可能需要一些帮助! 这是我的部分代码(嗯,完整的mandelbrot函数): 这是输出的图片:(抱歉,它不是很漂亮,颜色不是我的首要任务,但我一定会尽快处理它们,只要我弄清楚变焦!) 曼德布罗特 我希望能够做到的是: 左键单击- (已经有一

  • 使 UIScrollView 中的图片支持手势缩放。双击图片可以放大图片,或者pinch(捏合)手势可以缩放图片。基本原理是UIScrollView中嵌套UIScrollView,然后再嵌套UIImageView,可对UIImageView进行伸缩。 [Code4App.com]