Увеличение до точки мыши с помощью ScrollView и ViewBox в Wpf

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

Если вы хотите увидеть, что происходит ... Вот мой текущий файл решения.

Or

Вот код:

Просмотр Xaml

<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


}

person Lukehb    schedule 29.04.2012    source источник


Ответы (1)


Решено, он изменил задний код для масштабирования представления:

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;

Если кому-то интересно, ЗДЕСЬ - это готовый файл решения с панорамирование тоже реализовано.

person Lukehb    schedule 02.05.2012