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

时间:2014-02-01 18:05:56

标签: c# wpf xaml wpf-controls

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

<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,以避免手动摆弄坐标?

1 个答案:

答案 0 :(得分:1)

    {li>

    CenterX=".5" CenterY=".5"中的ScaleTransform是不必要的。它所做的就是增加一个微小的平移变换(半像素)。

  1. 要从转换位置获取源位置,您需要使用逆转换(Inverse的{​​{1}}属性)。这是Transform错误的来源。

  2. 要更改转换原点,首先需要减去半个画布大小,然后转换,然后再添加一半画布大小。

    X-30
  3. 完整样本:

    <强> 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>