WPF应用程序形状缩放,图像平移/缩放,缩放的形状单击

问题描述

我正在制作一个带有地图图像的wpf应用程序,用户应该能够缩放和平移图像。还有一个矩形形状(在运行时创建)的集合,这些形状显示在国家名称上并且可以单击。

我将图像拉伸属性当前设置为“无”,因为如果将其设置为统一形状,则初始形状位置将与图像上的城市名称不匹配。如果将“拉伸”设置为“均匀”,如何修改形状的起始位置?

如果我和形状集合是Grid元素中的单独元素,如何实现平移?

如何确定在MouseLeftButtonDown处理程序中单击了哪些形状?

这是我的xaml

<Window x:Class="IMAGETRANSFORM.ShellView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:cal="http://www.caliburnproject.org"
        WindowState="Maximized"
         cal:Message.Attach="[Event MouseWheel] = [Action OnMouseWheel($source,$eventArgs)]">

   <Grid>
      <Image Source="{Binding imgsource}"
             Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top">
         <Image.RenderTransform>
            <ScaleTransform  x:Name="scale" 
                                 ScaleX="{Binding ZoomScale}"
                                 ScaleY="{Binding ZoomScale}"
                                 CenterX="0.0" CenterY="0.0"></ScaleTransform>
         </Image.RenderTransform>

      </Image>

      <ItemsControl ItemsSource="{Binding RectItems}">
         <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
               <Canvas>
                  <Canvas.RenderTransform>
                     <ScaleTransform  
                                 ScaleX="{Binding ZoomScale}"
                                 ScaleY="{Binding ZoomScale}"
                                 CenterX="0.0" CenterY="0.0" />
                  </Canvas.RenderTransform>
               </Canvas>
            </ItemsPanelTemplate>
         </ItemsControl.ItemsPanel>
         <ItemsControl.ItemContainerStyle>
            <Style targettype="ContentPresenter">
               <Setter Property="Canvas.Left" Value="{Binding X}"/>
               <Setter Property="Canvas.Top" Value="{Binding Y}"/>
            </Style>
         </ItemsControl.ItemContainerStyle>
         <ItemsControl.ItemTemplate>
            <DataTemplate>
               <Rectangle Width="{Binding Width}" 
                               Height="{Binding Height}" 
                               Fill="Transparent"
                               stroke="Black" strokeThickness="3"
                          cal:Message.Attach="[Event MouseLeftButtonDown] = [Action ShapeClicked($source,$eventArgs)]">

               </Rectangle>
            </DataTemplate>
         </ItemsControl.ItemTemplate>
      </ItemsControl>
   </Grid>
</Window>

这是我的viewmodel CS代码

using System;
using System.Collections.ObjectModel;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace IMAGETRANSFORM
{
   public class RectItem
   {
      public double X { get; set; }
      public double Y { get; set; }
      public double Width { get; set; }
      public double Height { get; set; }
   }

   public class Shellviewmodel : Caliburn.Micro.PropertyChangedBase,IShell
   {

      private BitmapImage _imgsrc;

      public BitmapImage imgsource
      {
         get { return _imgsrc; }
         set { _imgsrc = value; NotifyOfPropertyChange(() => imgsource); }
      }

      private double _zoomscale;

      public double ZoomScale
      {
         get { return _zoomscale; }
         set { _zoomscale = value; NotifyOfPropertyChange(() => ZoomScale); }
      }

      public ObservableCollection<RectItem> RectItems { get; set; }

      public Shellviewmodel()
      {
         ZoomScale = 1.0;

         RectItems = new ObservableCollection<RectItem>();
         RectItem ri = new RectItem();
         ri.X = 290;
         ri.Y = 130;
         ri.Height = 36;
         ri.Width = 127;
         RectItems.Add(ri);


         BitmapImage bi = new BitmapImage();
         bi.BeginInit();
         bi.UriSource = new Uri(@"D:\EMap.png");
         bi.EndInit();
         imgsource = bi;


      }

      public void ShapeClicked(object sender,MouseButtonEventArgs e)
      {
         Rectangle r = sender as Rectangle;
         double x = Canvas.GetLeft(r);
         double y = Canvas.GetTop(r);
      }


      public void OnMouseWheel(object sender,MouseWheelEventArgs e)
      {
         if (e.Delta > 0)
         {
            //scrolled up...
            ZoomScale += ZoomScale * 0.1;
         }
         else if (e.Delta < 0)
         {
            //scrolled down...
            ZoomScale -= ZoomScale * 0.1;
         }
      }

   }
}

解决方法

有很多方法可以做到这一点,但是基本上您应该缩放画布,而不是单个元素。如果您需要完整的工作示例,请查看my Perfy application,该示例显示了画布上可缩放和可滚动的元素。您要查找的内容的核心是MainWindow.xaml文件,该文件基本上可以归结为:

<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
    <ItemsControl ItemsSource="{Binding CanvasItems}">
        <ItemsControl.LayoutTransform>
            <ScaleTransform ScaleX="{Binding Zoom}" ScaleY="{Binding Zoom}" />
        </ItemsControl.LayoutTransform>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemContainerStyle>
            <Style TargetType="{x:Type ContentPresenter}">
                <Setter Property="Canvas.Left" Value="{Binding X}" />
                <Setter Property="Canvas.Top" Value="{Binding Y}" />
            </Style>
        </ItemsControl.ItemContainerStyle>
    </ItemsControl>
</ScrollViewer>

请注意,我已经删除了原始代码中用于调整RenderTransform的部分,因为该部分仅用于水平翻转整个画布。 ItemControl的LayoutTransform负责缩放。

您还询问了如何检测鼠标单击的元素。有几种方法可以做到这一点,但是我通常给每个画布元素一个自己的包含ICommand处理程序的视图模型,然后将一个行为添加到该元素的模板中以在单击时调用它(请参阅原始代码中的behaviors:MouseCaptureBehavior)。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...