WPF Training – Drag and Drop Trong WPF Part II

Sau bài "WPF Training – Drag and Drop Trong WPF Part I" nói về Drag-Drop, bài tiếp theo tôi xin nói về một Library hỗ trợ việc này theo hướng đơn giản mà hiệu quả cũng như không kém phần đẹp mắt và tùy biến.


I> Tiếp cận


Thư viện GongSolutions.Wpf.DragDrop là một sự nỗi bậc trong vấn đề Implement Drag-Drop WPF. Thư viện này có một số điểm nỗi bậc như sau:

  1. Hỗ trợ phát triển với mô hình MVVM, có nghĩa là phần Behavior có thể được đặc trong một ViewModel thay vì CodeBehind.

  2. Có nhiều sự lựa chọn khi sử dụng, hỗ trợ cả về vấn đề Drag-Drop phục vụ cho việc thay đổi Index

  3. Có thể làm việc với TreeViews

  4. Cho phép tùy chọn mặc định hoặc tự định nghĩa cách thể hiện trực quan cho Drag-Drop.


Các bạn có thể tham khảo Source tại đây

II> Ứng dụng mẫu


Công việc của bạn là tạo một project WPF Application và add reference thư viện tải ở trên. Sau đó thiết kế project theo mô hình MVVM cơ bản; hai View và một ViewModels. cấu trúc project như này:

drag drop tuanpham

Chúng ta chỉ cần quan tâm đến hai file. "ListBoxDDView.xaml" là phần View của ListBox với chức năng Drag-Drop với DataContext là "ListBoxDDViewModel.cs". Ngoài ra, "MainWindowVew" là View chính chứa 2 "ListBoxDDView" và "PerItem.cs" chính là class thể hiện một Item trong ListBox.

PerItem.cs

[code language="csharp"]
public class PerItem
{
public string Name { set; get; }

public PerItem(string name)
{
Name = "Item: " + name;
}
}
[/code]

Design phần View với code như sau(xem về DataTemplate để hiểu)
ListBoxDDView.xaml

[code language="xml"]
<Grid>
<ListBox ItemsSource="{Binding DataCollection, UpdateSourceTrigger=PropertyChanged}"
Foreground="White"
HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Margin="2,2,2,2" TextWrapping="Wrap" IsReadOnly="True"
Text="{Binding Name}" VerticalAlignment="Top" VerticalContentAlignment="Center"
BorderBrush="#FF007ACC" Template="{DynamicResource TextBoxBaseTemplate}"
Background="{x:Null}" Padding="0,2"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
[/code]

Sau đó chúng ta thêm Attach Property vào code trên để dùng được Drag-Drop

[code language="xml"]
<Grid>
<ListBox ItemsSource="{Binding DataCollection, UpdateSourceTrigger=PropertyChanged}"
DragDrop:DragDrop.DropHandler="{Binding}"
DragDrop:DragDrop.IsDragSource="True"
DragDrop:DragDrop.IsDropTarget="True"
Foreground="White"
HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Margin="2,2,2,2" TextWrapping="Wrap" IsReadOnly="True"
Text="{Binding Name}" VerticalAlignment="Top" VerticalContentAlignment="Center"
BorderBrush="#FF007ACC" Template="{DynamicResource TextBoxBaseTemplate}"
Background="{x:Null}" Padding="0,2"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
[/code]

Chú ý:

  1. Để dùng được Attached Property trên ta cần reference thư viện <xmlns:DragDrop="clr-namespace:GongSolutions.Wpf.DragDrop;assembly=GongSolutions.Wpf.DragDrop">

  2. DragDrop.DropHandler="{Binding}" chỉ ra method sẽ implement cho việc Drop data

  3. DragDrop.IsDragSource="True" nói rằng Control là nguồn Drag(tức có thể kéo Item của nó)
    và nó sẽ gọi implement của method Drag

  4. DragDrop.IsDropTarget="True" ý rằng Control này cho phép Drag data vào nó sẽ gọi implement của method Drop


Sau đó implement cho phần VewModel, model này implement của interface IDropTarget
ListBoxDDViewModel.cs

[code language="csharp"]
public class ListBoxExViewModel : IDropTarget
{
public ObservableCollection<PerItem> DataCollection { set; get; }
public bool IsAllowMove { set; get; }

public ListBoxExViewModel()
{
DataCollection = new ObservableCollection<PerItem>();
for (int i = 0; i < 20; i++) {
DataCollection.Add(new PerItem(i.ToString()));
}
}

// Được gọi khi bạn Kéo một Item đi
public void DragOver(IDropInfo dropInfo)
{
if (IsAllowMove)
{
// Hiệu ứng Drag
dropInfo.Effects = DragDropEffects.Move;
}
else
{
// Hiệu ứng Drag
dropInfo.Effects = DragDropEffects.Copy;
}
// Hiệu ứng Drop
dropInfo.DropTargetAdorner = DropTargetAdorners.Insert;
}

// Được gọi khi một Item được Drag lên một Control cho phép Drop
public void Drop(IDropInfo dropInfo)
{
var data = dropInfo.Data as PerItem;

// Lấy data và xử lý
if (data != null)
{
DataCollection.Add(data);
var source = dropInfo.TargetCollection;
}
else
{
var dataList = dropInfo.Data as IList<PerItem>;
if (dataList != null && dataList.Count > 0)
{
foreach (PerItem perItem in dataList)
{
DataCollection.Add(perItem);
}
}
}
}
}
[/code]

Chú ý: các bạn có thể implement interface IDragSource để có nhiều xử lý hơn khi Drag

Kết quả drag drop gong drag drop  tuanphamĐể đẹp hơn chúng ta cần thêm đoạn code sau vào phần View( vào thẻ ListBox trong  ListBoxDDDView.xaml)

  1. Hiệu ứng kèm theo chuột cho các Item được Drag: DragDrop:DragDrop.UseDefaultDragAdorner="True" [1]

  2. Hiệu ứng chú thích/ hiệu ứng Drag của chuột: DragDrop:DragDrop.UseDefaultEffectDataTemplate="True"

  3. Thêm hiệu ứng kèm theo chuột cho các Item được Drap: DragDrop:DragDrop.DragAdornerTemplate="{StaticResource DragAdorner}" với DragAdorner là một Template do bạn tạo(không dùng chung với [1]).

  4. Và còn nhiều tùy chọn khác bạn có thể tìm hiểu ......


Source tham khảo tại đây. Chúc các bạn thành công!

Phạm Tuân


Chúc các bạn thành công!
PHẠM TUÂN