我正在制作绘图应用程序。因为我想要与数学图相同的行为,所以我将以下转换应用于带有数据点的 Canvas :
<UserControl.Resources>
<TransformGroup x:Key="CanvasTransform">
<TranslateTransform X="30" Y="30"/>
<ScaleTransform ScaleX="1" ScaleY="-1" CenterX=".5" CenterY=".5" />
</TransformGroup>
</UserControl.Resources>
这里是使用的转换:
<ListBox>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<Canvas>
<Canvas.RenderTransformOrigin>
<Point X="0.5" Y="0.5"/>
</Canvas.RenderTransformOrigin>
<Canvas.RenderTransform>
<Binding Source="{StaticResource CanvasTransform}"/>
</Canvas.RenderTransform>
</Canvas>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
到目前为止一切顺利。问题在于向绘图添加点。因为鼠标单击事件返回的是窗口坐标中的位置,所以没有用。该点添加在错误的位置,因为它在添加后发生了转换。
例如 Canvas 高 400 个单位。我点击鼠标左上角位置是 [X=10, Y=10]
这个点被添加到绘图中并渲染。渲染变换然后使用 [10,10] 点并计算它的新位置:[X=40,Y=360]
(窗口坐标)。
这意味着我点击上角,点出现在下角。这实际上是正确的行为。
我的问题是,如何在存储点之前手动应用渲染变换,这样点就会出现在鼠标下。
到目前为止,我尝试了以下操作:
var trans = Resources["CanvasTransform"] as TransformGroup;
var mouse = e.GetPosition(this); // mouse position relative to canvas
var newPoint = trans.Transform(mouse);
但是在这个转换之后 newPoint
有以下坐标 [40,-39]
。我再次知道为什么结果是这样。转换的原点是 [0,0]
,转换为 29
可能是由于舍入误差。
现在我可以采用这个新点并手动更改值 - 从 X 坐标减去 30
,然后将 Canvas.ActualHeight
添加到 Y 坐标,这将固定位置.
但那有什么意义呢?
我的问题是:是否有可能以与渲染相同的方式应用 RenderTransform
,以避免手动调整坐标?
最佳答案
CenterX=".5"CenterY=".5"
在ScaleTransform
中是不必要的。它所做的只是添加一个微小的平移变换(半像素)。要从转换后的位置获取源位置,您需要使用逆变换(
Transform
的Inverse
属性)。这就是X-30
错误的来源。要更改变换原点,您需要先减去一半 Canvas 大小,然后进行变换,然后添加一半 Canvas 大小。
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;
完整示例:
MainWindow.xaml
<Window x:Class="So21501609WpfMouseRenderTransform.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" SizeToContent="WidthAndHeight">
<Control.Resources>
<TransformGroup x:Key="CanvasTransform">
<TranslateTransform X="30" Y="30"/>
<ScaleTransform ScaleX="1" ScaleY="-1" CenterX=".5" CenterY=".5"/>
</TransformGroup>
<Style TargetType="TextBlock">
<Setter Property="Background" Value="SkyBlue"/>
</Style>
</Control.Resources>
<ItemsControl x:Name="lstItems" MouseDown="LstItems_OnMouseDown" Width="400" Height="400" Background="Transparent">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas>
<Canvas.RenderTransformOrigin>
<Point X="0.5" Y="0.5"/>
</Canvas.RenderTransformOrigin>
<Canvas.RenderTransform>
<Binding Source="{StaticResource CanvasTransform}"/>
</Canvas.RenderTransform>
</Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.Items>
<TextBlock Canvas.Left="10" Canvas.Top="10" Text="10 10"/>
<TextBlock Canvas.Left="10" Canvas.Top="300" Text="10 300"/>
<TextBlock Canvas.Left="300" Canvas.Top="300" Text="300 300"/>
<TextBlock Canvas.Left="300" Canvas.Top="10" Text="300 10"/>
</ItemsControl.Items>
</ItemsControl>
</Window>
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);
}
}
}
关于c# - 如何将渲染变换应用于鼠标位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21501609/