C# 如何将渲染变换应用于鼠标位置

C# 如何将渲染变换应用于鼠标位置,c#,wpf,xaml,wpf-controls,C#,Wpf,Xaml,Wpf Controls,我正在做一个绘图应用程序。因为我想要与数学图相同的行为,所以我将以下转换应用于具有数据点的画布: <UserControl.Resources> <TransformGroup x:Key="CanvasTransform"> <TranslateTransform X="30" Y="30"/> <ScaleTransform ScaleX="1" ScaleY="-1" CenterX=".5" CenterY

我正在做一个绘图应用程序。因为我想要与数学图相同的行为,所以我将以下转换应用于具有数据点的画布:

<UserControl.Resources>
    <TransformGroup x:Key="CanvasTransform">
        <TranslateTransform X="30" Y="30"/>
        <ScaleTransform ScaleX="1" ScaleY="-1" CenterX=".5" CenterY=".5" />
    </TransformGroup>
</UserControl.Resources>
但是在这个转换之后,
newPoint
有以下坐标
[40,-39]
。我再次知道为什么结果是这样。转换的原点是
[0,0]
,而转换是
29
,可能是由于舍入错误

现在,我可以利用这个新点手动更改值-从X坐标减去
30
,然后将
Canvas.ActualHeight
添加到Y坐标,这将固定位置

但那又有什么意义呢

我的问题是:有没有可能像渲染器那样应用
渲染转换
,以避免手动修改坐标

  • ScaleTransform
    中的
    CenterX=“.5”CenterY=“.5”
    是不必要的。它所做的只是添加一个微小的平移变换(半像素)

  • 要从变换后的位置获取源位置,需要使用逆变换(
    Transform
    inverse
    属性)。这就是
    X-30
    错误的来源

  • 要更改转换原点,首先需要减去画布大小的一半,然后进行转换,然后添加画布大小的一半

    var origin = new Point(lstItems.ActualWidth / 2, lstItems.ActualHeight / 2);
    var transform = ((TransformGroup)Resources["CanvasTransform"]).Clone();
    transform.Children.Insert(0, new TranslateTransform(-origin.X, -origin.Y));
    transform.Children.Add(new TranslateTransform(origin.X, origin.Y));
    _transform = transform.Inverse;
    
  • 完整样本:

    main window.xaml

    
    
    MainWindow.xaml.cs

    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows.Media;
    
    namespace So21501609WpfMouseRenderTransform
    {
        public partial class MainWindow
        {
            private GeneralTransform _transform;
    
            public MainWindow ()
            {
                InitializeComponent();
                Loaded += OnLoaded;
            }
    
            private void OnLoaded (object sender, RoutedEventArgs routedEventArgs)
            {
                var origin = new Point(lstItems.ActualWidth / 2, lstItems.ActualHeight / 2);
                var transform = ((TransformGroup)Resources["CanvasTransform"]).Clone();
                transform.Children.Insert(0, new TranslateTransform(-origin.X, -origin.Y));
                transform.Children.Add(new TranslateTransform(origin.X, origin.Y));
                _transform = transform.Inverse;
            }
    
            private void LstItems_OnMouseDown (object sender, MouseButtonEventArgs e)
            {
                Point pos = _transform.Transform(e.GetPosition(lstItems));
    
                var item = new TextBlock { Text = pos.ToString() };
                Canvas.SetLeft(item, pos.X);
                Canvas.SetTop(item, pos.Y);
                lstItems.Items.Add(item);
            }
        }
    }
    
    var origin = new Point(lstItems.ActualWidth / 2, lstItems.ActualHeight / 2);
    var transform = ((TransformGroup)Resources["CanvasTransform"]).Clone();
    transform.Children.Insert(0, new TranslateTransform(-origin.X, -origin.Y));
    transform.Children.Add(new TranslateTransform(origin.X, origin.Y));
    _transform = transform.Inverse;
    
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows.Media;
    
    namespace So21501609WpfMouseRenderTransform
    {
        public partial class MainWindow
        {
            private GeneralTransform _transform;
    
            public MainWindow ()
            {
                InitializeComponent();
                Loaded += OnLoaded;
            }
    
            private void OnLoaded (object sender, RoutedEventArgs routedEventArgs)
            {
                var origin = new Point(lstItems.ActualWidth / 2, lstItems.ActualHeight / 2);
                var transform = ((TransformGroup)Resources["CanvasTransform"]).Clone();
                transform.Children.Insert(0, new TranslateTransform(-origin.X, -origin.Y));
                transform.Children.Add(new TranslateTransform(origin.X, origin.Y));
                _transform = transform.Inverse;
            }
    
            private void LstItems_OnMouseDown (object sender, MouseButtonEventArgs e)
            {
                Point pos = _transform.Transform(e.GetPosition(lstItems));
    
                var item = new TextBlock { Text = pos.ToString() };
                Canvas.SetLeft(item, pos.X);
                Canvas.SetTop(item, pos.Y);
                lstItems.Items.Add(item);
            }
        }
    }