Powiększanie do punktu myszy za pomocą ScrollView i ViewBox w Wpf
Mam kilka ścieżek na ekranie w wpf. Użyte współrzędne są dość małe, więc zostały wykonane w celu wypełnienia ekranu polem widzenia. Próbuję teraz zaimplementować funkcję panoramowania i powiększania. Chciałbym być w stanie powiększyć obraz wszędzie tam, gdzie mysz jest w stosunku do interfejsu użytkownika (tzn. Środek ekranu powiększonego jest równy współrzędnym myszy). Obecny wynik jest taki, że środek ekranu po powiększeniu nie odzwierciedla dokładnej pozycji myszy na interfejsie użytkownika.
Jeśli chcesz zobaczyć, co się dzieje ...Oto mój aktualny plik rozwiązania.
Lub
Oto jakiś kod:
Zobacz Xaml
<code><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> </code>
Zobacz model
<code>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(); } } </code>
Wyświetl kod za
<code>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 } </code>