我想在WPF中使用Shapes以类似于几何图表或绘图的方式显示一些数学定义的对象(点,折线,参考轴)。我想使用Shapes因为它们的交互性,因为用户应该点击它们,用鼠标悬停突出显示它们等。
Shape对象本身应在ViewModel中数据绑定到它们的几何定义。我可以根据最方便的选择(PointCollection,PathFigure,Point等)来选择每个属性的类型。
问题是:到目前为止,我正在尝试使用Canvas容器,它具有一些特殊的布局特征,这使我很难做到正确。具体来说,它的起源位于左上角,所以我的形状显得颠倒,除非我使用RenderTransform(我不反对);
除此之外,我在ViewModel(类型为Rect
)中有一个BoundingBox属性,它应该用于控件内的“fit”或“autozoom”,但由于模型坐标不是屏幕坐标,我会有应用一些变换。
不幸的是,我只能将变换应用于Geometries,我可以使用带有DrawingImage的Image作为源,使用描述形状的GeometryDrawings。但是,我首先失去了形状所需的所有特征(主要是造型和交互)。
这就是我陷入困境的原因,所以我的问题归结为:
“我如何转换形状的几何体,使它们正确定位在画布中的'参考视口'内?”
这是一些令人不满意的代码,Image控件显示所需的布局:
XAML:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DrawingGraficos"
x:Class="DrawingGraficos.MainWindow"
x:Name="Window"
Title="MainWindow"
Width="204.333" Height="181">
<Window.DataContext>
<local:DesenhoViewModel/>
</Window.DataContext>
<Window.Resources>
<local:TranslacaoConverter x:Key="TranslacaoConverter"/>
</Window.Resources>
<UniformGrid Rows="0" Columns="2">
<Canvas x:Name="canvasviewport">
<Polygon Points="{Binding BoundingBoxCorners}" Fill="LightGray"/>
<Path Stroke="Red" StrokeThickness="2" Data="{Binding GeometriaLinhaSimetria}"/>
</Canvas>
<Image>
<Image.LayoutTransform>
<ScaleTransform ScaleY="-1" CenterY=".5"/>
</Image.LayoutTransform>
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<DrawingGroup>
<DrawingGroup.ClipGeometry>
<RectangleGeometry Rect="{Binding Limites}"/>
</DrawingGroup.ClipGeometry>
<GeometryDrawing Brush="LightGray">
<GeometryDrawing.Geometry>
<RectangleGeometry Rect="{Binding Limites}"/>
</GeometryDrawing.Geometry>
</GeometryDrawing>
<GeometryDrawing Geometry="{Binding GeometriaLinhaSimetria}">
<GeometryDrawing.Pen>
<Pen Brush="Red" Thickness="2"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingGroup>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
</Image>
</UniformGrid>
</Window>
视图模型:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Miotec.MVVM;
using System.Windows;
using System.Windows.Media;
namespace DrawingGraficos
{
public class DesenhoViewModel : ViewModelBase {
public Rect Limites {
get {
double largura = 70;
double altura = 100;
return new Rect(new Point(-largura*0.5,-30), new Point(largura*0.5,altura-30));
}
}
public PointCollection BoundingBoxCorners {
get {
return new PointCollection() {
Limites.BottomLeft, Limites.TopLeft, Limites.TopRight, Limites.BottomRight
};
}
}
public Point Origem { get { return new Point(0,0); } }
public List<Point> LinhaSimetria {
get {
return new List<Point> {
new Point(-3,-20),
new Point(0,-15),
new Point(2,-10),
new Point(4,-5),
new Point(4,0),
new Point(2,5),
new Point(2,10),
new Point(0,15),
new Point(-2,20),
new Point(-2,25),
new Point(-2,30),
new Point(-2,35)
};
}
}
public Geometry GeometriaLinhaSimetria {
get {
var sb = new StringBuilder("M");
foreach (var p in LinhaSimetria) {
sb.AppendFormat(" {0};{1}", p.X, p.Y);
}
string result = sb.ToString().Replace(",",".").Replace(";",",");
return Geometry.Parse(result);
}
}
}
}