Tôi sẽ chỉ cách tạo ứng dụng WPF với mẫu MVVM cho 2D-Poliline với các đỉnh có thể kéo được.
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");
}
}
}
Lớp ViewModelBase
chỉ chứa một thực hiện của giao diện INotifyPropertyChanged
. Điều này là cần thiết để phản ánh những thay đổi của thuộc tính clr trên biểu diễn trực quan.
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; }
}
Nó có tham chiếu đến các điểm, vì vậy những thay đổi sẽ được nhận tự động.
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; }
}
Nó chứa một dữ liệu mẫu các điểm và đường
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>
Dưới đây là rất nhiều thủ đoạn. Trước hết, các số ItemsControls
này không dựa trên dọc StackPanel
, nhưng trên Canvas
.Các ItemsControl
của các điểm áp dụng một mẫu container đặc biệt với một mục tiêu để đặt các mục trên tọa độ cần thiết. Nhưng ItemsControl
của dòng không yêu cầu các mẫu như vậy, và nó là lạ tại một số điểm. Hai DataTemplates cuối cùng là hiển nhiên.
PointView.xaml
<Ellipse Width="12" Height="12" Stroke="Red" Margin="-6,-6,0,0" Fill="Transparent"/>
Left và Top lề đều bình đẳng với một nửa của Width
và Height
. Chúng tôi có một số Fill
trong suốt vì thuộc tính này không có giá trị mặc định và các sự kiện của chuột không hoạt động.
Điều đó gần như tất cả. Chỉ có chức năng kéo-thả-thả.
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);
}
}
Vì vậy, mẫu của bạn được thực hiện sử dụng 2 file XAML và 3 viewmodels.
@Tom Tôi khuyên bạn nên thử một số thứ trong mã thay vì trong Xaml nếu Xaml đang thúc đẩy bạn hạt. –
@Tom Tôi khuyên bạn nên bắt đầu với điều khiển 'Canvas' và chơi với các yếu tố bổ sung có lập trình cho nó và thay đổi vị trí của chúng. Bạn có thể có được một cảm giác để làm việc với đường dẫn, nhưng không có thêm đầu nồi hơi của Xaml để tranh với cùng một lúc. –
Bất kỳ phiếu bầu nào để đóng, vui lòng giải thích lý do. Đó là một câu hỏi hợp lệ. Cảm ơn bạn. –