我将展示如何使用带可拖动顶点的2D-Poliline构建MVVM模式的WPF应用程序。
PointViewModel.cs
public class PointViewModel: ViewModelBase
{
public PointViewModel(double x, double y)
{
this.Point = new Point(x, y);
}
private Point point;
public Point Point
{
get { return point; }
set
{
point = value;
OnPropertyChanged("Point");
}
}
}
类ViewModelBase
只包含接口INotifyPropertyChanged
的实现。这对于反映视觉表示中clr属性的变化是必要的。
LineViewModel.cs
public class LineViewModel
{
public LineViewModel(PointViewModel start, PointViewModel end)
{
this.StartPoint = start;
this.EndPoint = end;
}
public PointViewModel StartPoint { get; set; }
public PointViewModel EndPoint { get; set; }
}
它具有点引用,所以更改将自动接收。
MainViewModel.cs
public class MainViewModel
{
public MainViewModel()
{
this.Points = new List<PointViewModel>
{
new PointViewModel(30, 30),
new PointViewModel(60, 100),
new PointViewModel(50, 120)
};
this.Lines = this.Points.Zip(this.Points.Skip(1).Concat(this.Points.Take(1)),
(p1, p2) => new LineViewModel(p1, p2)).ToList();
}
public List<PointViewModel> Points { get; set; }
public List<LineViewModel> Lines { get; set; }
}
它包含点的采样数据和线
MainVindow.xaml
<Window.Resources>
<ItemsPanelTemplate x:Key="CanvasPanelTemplate">
<Canvas/>
</ItemsPanelTemplate>
<Style x:Key="PointListBoxItem">
<Setter Property="Canvas.Left" Value="{Binding Point.X}"/>
<Setter Property="Canvas.Top" Value="{Binding Point.Y}"/>
</Style>
<DataTemplate x:Key="LineTemplate">
<Line X1="{Binding StartPoint.Point.X}" X2="{Binding EndPoint.Point.X}" Y1="{Binding StartPoint.Point.Y}" Y2="{Binding EndPoint.Point.Y}" Stroke="Blue"/>
</DataTemplate>
<DataTemplate x:Key="PointTemplate">
<view:PointView />
</DataTemplate>
</Window.Resources>
<Grid>
<ItemsControl ItemsSource="{Binding Lines}" ItemsPanel="{StaticResource CanvasPanelTemplate}" ItemTemplate="{StaticResource LineTemplate}"/>
<ItemsControl ItemsSource="{Binding Points}" ItemContainerStyle="{StaticResource PointListBoxItem}" ItemsPanel="{StaticResource CanvasPanelTemplate}"
ItemTemplate="{StaticResource PointTemplate}"/>
</Grid>
这里有很多花样。首先,这些ItemsControls
不是基于垂直StackPanel
,而是基于Canvas
。点的ItemsControl
应用特定容器模板,其目标是将项目放置在必要的坐标上。但是线的ItemsControl
不需要这样的模板,并且在某些时候很奇怪。最后两个DataTemplates是显而易见的。
PointView.xaml
<Ellipse Width="12" Height="12" Stroke="Red" Margin="-6,-6,0,0" Fill="Transparent"/>
Left和Top利润率等于Width
和Height
的一半。我们有一个透明的Fill
,因为这个属性没有默认值,鼠标的事件不起作用。
这几乎都是。只有拖放功能仍然存在。
PointView.xaml.cs
public partial class PointView : UserControl
{
public PointView()
{
InitializeComponent();
this.MouseLeftButtonDown += DragSource_MouseLeftButtonDown;
this.MouseMove += DragSource_MouseMove;
}
private bool isDraggingStarted;
private void DragSource_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
this.isDraggingStarted = true;
}
private void DragSource_MouseMove(object sender, MouseEventArgs e)
{
if (isDraggingStarted == true)
{
var vm = this.DataContext as PointViewModel;
var oldPoint = vm.Point;
DataObject data = new DataObject("Point", this.DataContext);
DragDropEffects effects = DragDrop.DoDragDrop(this, data, DragDropEffects.Move);
if (effects == DragDropEffects.None) //Drag cancelled
vm.Point = oldPoint;
this.isDraggingStarted = false;
}
}
MainVindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainViewModel();
this.AllowDrop = true;
this.DragOver += DropTarget_DragOver;
}
private void DropTarget_DragOver(object sender, DragEventArgs e)
{
var vm = e.Data.GetData("Point") as PointViewModel;
if (vm != null)
vm.Point = e.GetPosition(this);
}
}
所以你的样品是使用2个XAML文件和3周的ViewModels完成。
@Tom我会建议在代码中尝试一些事情,而不是在Xaml中,如果Xaml驱使你疯了。 – 2011-01-22 13:29:57
@Tom我会建议从一个`Canvas`控件开始,并以编程方式向它添加元素并改变它们的位置。你可以感受到与路径一起工作的感觉,但是如果没有Xaml的头部锅炉同时进行对抗的话。 – 2011-01-22 13:42:49
无论谁投票结束,请解释原因。这是一个有效的问题。谢谢。 – 2011-01-22 13:59:35