2014-02-01 2 views
3

Я делаю приложение для нанесения рисунка. Потому что я хочу такое же поведение, как математические участки я применяю после трансформации в холст с точками данных:Как применить визуализацию Преобразование в положение мыши

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

До сих пор так хорошо. Проблема заключается в добавлении точек в график. Поскольку событие щелчка мыши возвращает позицию в координатах окна, это бесполезно. Точка добавляется в неправильном месте, потому что она преобразуется после добавления.

например. Холст высотой 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, вероятно, из-за ошибки округления.

Теперь я могу взять эту новую точку и вручную изменить значения - вычесть 30 из координаты X, а затем добавить Canvas.ActualHeight в координату Y, которая зафиксирует положение.

Но тогда в чем смысл?

Мой вопрос: можно ли использовать RenderTransform так же, как это делает rendere, чтобы избежать возиться с координатами?

ответ

1
  1. CenterX=".5" CenterY=".5" в ScaleTransform ненужно. Все, что он делает, добавляет крошечное преобразование перевода (полупиксельное).

  2. Чтобы получить исходное положение из преобразованного положения, вам необходимо использовать обратное преобразование (Inverse property of Transform). Здесь происходит ошибка X-30.

  3. Чтобы изменить начало трансформации, вы должны, во-первых, вычесть половину размера холста, затем преобразовать, а затем добавить половину размера холста.

    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); 
     } 
    } 
} 
+0

Спасибо, что сделал трюк. – jnovacho

Смежные вопросы