C# WPFで行うドラッグ&ドロップ操作
ドラッグ&ドロップは、オブジェクトをマウス操作で、移動する操作のことです。
ドラッグ元のし要素上で、マウスの左ボタンを押したままマウスを動かし、ドロップ先にマウスカーソルが移動したところで、マウスの左ボタンを離します。この操作で、ドラッグ元の要素をドロップ先に移動、あるいは、ドラッグ元の要素を選択できます。
TextBoxへのドロップ操作でファイル名を取得する
ファイル名を取得する方法には、オープン・ファイル・ダイアログを使用する方法に加えて、ドラッグ&ドロップがあります。コードを記述する場合、オープン・ファイル・ダイアログを使用する方法の方が明瞭です。アプリケーションを実際に操作する際は、感覚的に、ドラッグ&ドロップ操作のほうが明瞭です。
そのため、アプリケーションの操作性を考えると、どちらかだけを実装するのではなく、両方実装することが求められます。
C#のユーザーインターフェイスの実装には、Formアプリケーション、WPFアプリケーション、UWP、Xamarinが使われています。それぞれに実装方法、具体的には使用するクラスが異なります。そのため、MVVMと呼ばれる、表示と入力部分を独立させるデザインパターンの使用が推奨されています。興味があれば、導入を検討してみてください。
今回、C# WPFを用いで、ファイルをドラッグ&ドロップすることにより、ファイル名を取得するコードを確認してみたいと思います。
C# WPFで、TextBoxにファイルをドロップしてファイル名を取得する場合、TextBoxがもともとドラッグ&ドロップに対応しているため、ドロップのためのイベントの内容を記述する他に、イベントハンドラを追加する作業が必要です。
ドロップしたファイルのファイル名を表示するテキストボックス
WPFアプリ(.Net Framework)で、プロジェクトを新規作成します。
MainWindow.xamlに以下のコードを入力し、UIを作成します。
<Window x:Class="GetFileName.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="150" Width="350">
<DockPanel>
<Grid DockPanel.Dock="Bottom">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Grid.Column="0">Button01</Button>
<Button Grid.Column="1">Button02</Button>
</Grid>
<TextBox DockPanel.Dock="Top" Name="tb" TextWrapping="Wrap" AllowDrop="True" >
TextBox
</TextBox>
</DockPanel>
</Window>
ドロップを有効にするために、AllowDrop="True" に、テキストを折り返すために、TextWrapping="Wrap"属性を追加します。(注 Textboxは、ドラッグ&ドロップをすでに実装しているため、AllowDrop="True" を追加する必要はありません。)
DragOver イベントでは、ドラッグされている要素が、目的の要素であるかを確認し、目的の要素の場合のみ処理を行います。
ドラッグされている要素が、目的の要素であるかは、以下のコードで確認することができます。
e.Data.GetDataPresent(DataFormats.FileDrop)
要素の種類は、 DataFormatsで指定します。ここでは、ファイルであることを確認するために、FileDropを指定しています。
DragOverイベントでは、ドラッグされている要素の内容に合わせて、マウスポインタを変更します。
DragOver イベントは、ドラッグした状態でマウスポインタが、要素上にあるときイベントが発生し続けるので、イベント処理の最後で、 e.Handled = false;を記述しイベントをクリアします。
private void Tb_DragOver(object sender, DragEventArgs e)
{
// マウスポインタを変更する。
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
e.Effects = DragDropEffects.All;
}
else
{
e.Effects = DragDropEffects.None;
}
e.Handled = false;
}
次に、Dropイベントを追加します。
private void Tb_Drop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
// TextBoxの中身をクリアする。
tb.Text = string.Empty;
// ドロップしたファイル名を全部取得する。
string[] filenames = (string[])e.Data.GetData(DataFormats.FileDrop);
// 最初のファイルをTextBoxで
tb.Text = filenames[0];
}
}
ファイルのドロップは、e.Data.GetData(DataFormats.FileDrop)で、オブジェクト型として取得できます。
ファイル名を取得する場合は、string型の配列として取得します。
残念ながら、これだけでは、ドラッグ&ドロップ操作で、ファイルをドロップすることで、ファイル名をTextBoxに表示することはできません。
WPFのTextBox、RichTextBox、FlowDocumentコントーロールは、ドラッグ&ドロップ機能が組み込まれています。テキストを他のアプリケーションとの間で、ドラッグ&ドロップできます。
今回のように、ファイルをドロップして、TextBoxにファイル名を表示させる機能は、新たに追加する機能になります。このように、ドラッグ&ドロップ機能を持っている、これら3つのコントロールに、ドラッグ&ドロップ機能を追加するには、明示的に、AddHandler(RoutedEvent, Delegate, Boolean)メソッドを使用して、イベントハンドラを追加する必要があります。
MainWindow()メソッドに、イベントハンドラを追加します。
public MainWindow()
{
InitializeComponent();
tb.AddHandler(TextBox.DragOverEvent, new DragEventHandler(Tb_DragOver), true);
tb.AddHandler(TextBox.DropEvent, new DragEventHandler(Tb_Drop), true);
}
コード全体を示します。
MainWindow,xaml
<Window x:Class="GetFileName.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="150" Width="350">
<DockPanel>
<Grid DockPanel.Dock="Bottom">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Grid.Column="0">Button01</Button>
<Button Grid.Column="1">Button02</Button>
</Grid>
<TextBox DockPanel.Dock="Top" Name="tb" DragOver="Tb_DragOver" Drop="Tb_Drop" AllowDrop="True" TextWrapping="Wrap">
TextBox
</TextBox>
</DockPanel>
</Window>
MainWindow,xaml.cs
using System.Windows;
using System.Windows.Controls;
namespace GetFileName
{
/// <summary>
/// MainWindow.xaml の相互作用ロジック
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
tb.AddHandler(TextBox.DragOverEvent, new DragEventHandler(Tb_DragOver), true);
tb.AddHandler(TextBox.DropEvent, new DragEventHandler(Tb_Drop), true);
}
private void Tb_DragOver(object sender, DragEventArgs e)
{
// マウスポインタを変更する。
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
e.Effects = DragDropEffects.All;
}
else
{
e.Effects = DragDropEffects.None;
}
e.Handled = false;
}
private void Tb_Drop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
// TextBoxの中身をクリアする。
tb.Text = string.Empty;
// ドロップしたファイル名を全部取得する。
string[] filenames = (string[])e.Data.GetData(DataFormats.FileDrop);
tb.Text = filenames[0];
}
}
}
}