2023年6月12日

ZoomViewer

作者 dikangqie

ZoomViewer.xaml

<UserControl x:Class="WPFZoomText.ZoomViewer"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WPFZoomText"
             mc:Ignorable="d" 
             d:DesignHeight="500" d:DesignWidth="500">
    <Grid Background="Black" MouseDown="Grid_MouseDown" MouseUp="Grid_MouseUp" MouseWheel="Grid_MouseWheel"
          SizeChanged="Grid_SizeChanged">
        <Canvas Name="canvas" Canvas.Left="0" Canvas.Top="0">
            <Canvas.RenderTransform>
                <MatrixTransform x:Name="scale" />
            </Canvas.RenderTransform>
        </Canvas>
    </Grid>
</UserControl>

ZoomViewer.xaml.cs

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace WPFZoomText
{
    /// <summary>
    /// Interaction logic for ZoomViewer.xaml
    /// </summary>
    public partial class ZoomViewer : UserControl
    {
        /// <summary>
        /// Default constructor.
        /// </summary>
        public ZoomViewer()
        {
            InitializeComponent();
        }
        public Rect Domain { get; set; } = new Rect() { X = 0, Y = 0, Width = 30, Height = 30 };
        /// <summary>
        /// The set of the inner drawings (scale will affect to those drawings)
        /// </summary>
        public UIElementCollection Drawings
        {
            get
            {
                return canvas.Children;
            }
        }
        /// <summary>
        /// Scale the content to show everything.
        /// </summary>
        public void ZoomFit()
        {
            var s1 = ActualWidth / Domain.Width;
            var s2 = ActualHeight / Domain.Height;

            var m = new Matrix();
            var sc = s1 > s2 ? s2 : s1;
            m.Scale(sc, sc);
            var porig = m.Transform(new Point(Domain.Width / 2 + Domain.Left, Domain.Height / 2 + Domain.Top));
            var pdest = new Point(ActualWidth / 2, ActualHeight / 2);
            m.Translate(pdest.X - porig.X, pdest.Y - porig.Y);
            scale.Matrix = m;
        }

        private Point? draggingPoint = null;

        private void Grid_MouseDown(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;
            if (e.ChangedButton == MouseButton.Left)
            {
                if (e.ClickCount == 2)
                {
                    ZoomFit();
                } else
                {
                    draggingPoint = e.GetPosition(canvas);
                    ((Grid)sender).CaptureMouse();
                }
            }
        }
        private void Grid_MouseUp(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;
            if (e.ChangedButton == MouseButton.Left) {
                if (draggingPoint.HasValue)
                {
                    var pos = e.GetPosition(canvas);
                    var v = draggingPoint.Value - pos;

                    var m = scale.Matrix;
                    m.Translate(-v.X, -v.Y);
                    scale.Matrix = m;

                    ((Grid)sender).ReleaseMouseCapture();
                    draggingPoint = null;
                }
            }
        }
        private void Grid_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            e.Handled = true;

            var s = e.Delta > 0 ? 1.04 : 0.96;
            var m = scale.Matrix;
            var porig = m.Transform(e.GetPosition(canvas));

            m.ScaleAt(s, s, porig.X, porig.Y);
            scale.Matrix = m;
        }
        private void Grid_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            ZoomFit();
        }
    }
}