我正在制作一个绘图应用程序。因为我想要与数学图相同的行为,所以我将以下转换应用于带有数据点的画布:
<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>
到目前为止一切顺利。问题在于为绘图添加点。因为鼠标单击事件在窗口坐标中返回位置是没有用的。该点被添加到错误的位置,因为它在添加后被转换。
e.g。帆布高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
,以避免手动摆弄坐标?
答案 0 :(得分:1)
CenterX=".5" CenterY=".5"
中的ScaleTransform
是不必要的。它所做的就是增加一个微小的平移变换(半像素)。
要从转换位置获取源位置,您需要使用逆转换(Inverse
的{{1}}属性)。这是Transform
错误的来源。
要更改转换原点,首先需要减去半个画布大小,然后转换,然后再添加一半画布大小。
X-30
完整样本:
<强> MainWindow.xaml 强>
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.cs 强>
<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>