WPFでドラッグ&ドロップを実装するにはコードビハインドやビヘイビアを使用するなどがあるけど、僕はめんどくさがりなのでライブラリを使います。
Nugetにgong-wpf-dragdropがあったのでそれを使います。
今回はエクスプローラーからファイルをD&Dされたcsvファイルのパスを取得し、それをListBoxに表示するMVVMのアプリを作ります。
csvファイル以外は表示しないとします。
View
<Window x:Class="DragAndDropTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DragAndDropTest"
xmlns:dd="clr-namespace:GongSolutions.Wpf.DragDrop;assembly=GongSolutions.Wpf.DragDrop"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Grid>
<ListBox ItemsSource="{Binding Files}"
dd:DragDrop.IsDropTarget="True"
dd:DragDrop.DropHandler="{Binding}" />
</Grid>
</Window>
GongSolutions.WPF.DragDrop を使用するにはまずxamlに名前空間を追加します。
xmlns:dd="clr-namespace:GongSolutions.Wpf.DragDrop;assembly=GongSolutions.Wpf.DragDrop"
そして、D&Dを行いたい要素で
<ListBox ItemsSource="{Binding Files}"
dd:DragDrop.IsDropTarget="True"
dd:DragDrop.DropHandler="{Binding}" />
と記述します。
- DragDrop.IsDropTarget : ドロップ先のターゲット
- DragDrop.DropHandler : ドロップイベントのハンドラ
を表しています。今回はドロップされるだけなのでターゲットのみ宣言します。DropHandlerについては後ほど詳細を書きます。
ViewModel
using GongSolutions.Wpf.DragDrop;
using System.Windows;
using System.Linq;
using System.IO;
using System.Collections.ObjectModel;
namespace DragAndDropTest
{
public class MainWindowViewModel : IDropTarget
{
public ObservableCollection<string> Files { get; set; }
public MainWindowViewModel()
{
Files = new ObservableCollection<string>();
}
public void DragOver(IDropInfo dropInfo)
{
var dragFileList = ((DataObject)dropInfo.Data).GetFileDropList().Cast<string>();
dropInfo.Effects = dragFileList.Any(_ =>
{
return IsCsv(_);
}) ? DragDropEffects.Copy : DragDropEffects.None;
}
public void Drop(IDropInfo dropInfo)
{
var dragFileList = ((DataObject)dropInfo.Data).GetFileDropList().Cast<string>();
dropInfo.Effects = dragFileList.Any(_ =>
{
return IsCsv(_);
}) ? DragDropEffects.Copy : DragDropEffects.None;
foreach(var file in dragFileList)
{
if (IsCsv(file))
{
Files.Add(file);
}
}
}
private bool IsCsv(string data)
{
var extension = Path.GetExtension(data);
return extension != null && extension == ".csv";
}
}
}
IDropTargetがDropHandlerを実装するためのインターフェースです。DragOver() と Drop() を実装します。
今回はcsvファイルのみ受け付けるため、csvファイルかを判定する IsCsv() を実装しています。
まずDragOver()でcsvファイルがあれば受け付けるようにします。
var dragFileList = ((DataObject)dropInfo.Data).GetFileDropList().Cast<string>();
dropInfo.Effects = dragFileList.Any(_ =>
{
return IsCsv(_);
}) ? DragDropEffects.Copy : DragDropEffects.None;
GetFileDropList() でドロップされたファイルを取得しています。
そして、IsCsv()がtrueの時にDragDropEffectsがCopy(受け付ける)になり、falseの時にNone(受け付けない)にしています。
次にDrop()も同様にcsvファイルがあれば受け付けるようにし、foreach()内でIsCsv()を呼び、csvファイルでFiles.Add()でcsvファイルパスを追加すればListBoxにファイルパスが表示されます。
これでD&Dが簡単に実装できました。