DIYプログラミングにおいて、フォルダを選択したいケースはよくあります。
WindowsFormだとフォルダ選択ダイアログが標準で用意されていましたので、ツールボックスからドラッグ&ドロップで画面に張り付ければ事足たのですが、WPFの場合は残念ながら用意されていません。
WPFでの実装方法としては2種類あり、1つはNuget を使って WindowsAPICodePack-Shell というパッケージをインストールして使う方法、もう1つはWindowsForm に含まれているフォルダ選択ダイアログを呼び出す方法です。
今回は「ちょっとフォルダを選択したいだけなのに、わざわざ Nugetをつかうのも何だかな~」という方の為に、WindowsForm を使いたいと思います。
WindowsAPICodePack-Shell を使ったフォルダ選択ダイアログについては、こちらの記事に掲載していますので、興味のある方はご一読下さい。
また、今後のプログラミング作業効率化のために、ユーザーコントロールとして部品化してみようと思います。
フォルダ選択ダイアログの概要
今回作るのはこんな感じのユーザーコントロールです。
テキストボックスとフォルダダイアログを呼び出す為のフォルダアイコンで構成されています。
機能としては次の通りです。
- テキスト部にフォルダ名を直接入力
- フォルダ選択ダイアログの表示とフォルダの選択
- テキスト部にファイル又はフォルダをドラッグ&ドロップで入力
- フォルダ名が入力された時のイベント発生

右端のフォルダアイコンをクリックすると、次のレイアウトのフォルダ選択ダイアログが表示されます。

WindowsFormのフォルダ選択を使うには参照設定が必要
まず、ソリューションエクスプローラーの「参照」⇒「参照の追加」を選択し、参照マネージャを表示して下さい。

続けてアセンブリをクリックし、System.Windows.Forms を探してチェックを入れて、OKボタンをクリックします。

ユーザーコントロールの追加
ユーザーコントロールは、プロジェクト(今回の例では UserControlTest)を右クリックし、表示されるメニューから「追加」⇒「ユーザーコントロール(WPF)」を選択します。

新しい項目の追加ダイアログが表示されるので、名前をFolderSelectControl.xaml に替えて、追加ボタンをクリックします。

ダウンロード先
今回のソースコードのダウンロード先は次の通りです。
デモプログラムが含まれていますので、動作確認にお使いください。
尚、デモプログラムの仕様については、こちら に記載しています。
ソースコード
では、ソースコードを見ていきましょう。
画面(Xaml)は次の通りです。
<UserControl x:Class="CommonUserControl.FolderSelectControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:CommonUserControl"
mc:Ignorable="d" d:DesignWidth="522.194" Height="22">
<Grid UseLayoutRounding="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="250*"/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
<TextBox TextWrapping="Wrap" Grid.Row="0" x:Name="uxFolderName" PreviewKeyUp="uxFolderName_PreviewKeyUp"/>
<Button x:Name="uxOpenDialog" Grid.Column="1" Background="{x:Null}" BorderThickness="0" HorizontalAlignment="Right" Margin="0,3,1,1" VerticalContentAlignment="Center" Click="uxOpenDialog_Click">
<Image Source="Images/FolderOpen_exp_16x.png" />
</Button>
</Grid>
</UserControl>
C#のソースコードは次の通りです。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace CommonUserControl
{
/// <summary>
/// FolderSelectControl.xaml の相互作用ロジック
/// </summary>
public partial class FolderSelectControl : UserControl
{
/// <summary>
/// フォルダ選択完了時のイベント定義
/// </summary>
public event EventHandler<EventArgs> FolderSelected = delegate { };
/// <summary>
/// フォルダ名
/// </summary>
public string FolderName { get { return uxFolderName.Text; } set { uxFolderName.Text = value; } }
/// <summary>
/// コンストラクタ
/// </summary>
public FolderSelectControl()
{
InitializeComponent();
DragDrop();
}
/// <summary>
/// フォルダアイコンクリック時の処理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void uxOpenDialog_Click(object sender, RoutedEventArgs e)
{
// フォルダー参照ダイアログのインスタンスを生成
var dlg = new System.Windows.Forms.FolderBrowserDialog();
dlg.SelectedPath = FolderName;
dlg.Description = "フォルダを選択して下さい。";
// ダイアログを表示
if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
FolderName = dlg.SelectedPath;
FolderSelected(this, new EventArgs());
}
}
/// <summary>
/// ドラッグ&ドロップ処理
/// </summary>
private void DragDrop()
{
//ドラッグ&ドロップの処理
uxFolderName.PreviewDragOver += (sender, args) =>
{
args.Effects = (args.Data.GetDataPresent(DataFormats.FileDrop) ? DragDropEffects.Copy : DragDropEffects.None);
//コントロールの種類によって、下記の記述が必要(PreviewDropが効かない場合がある) なので、念のため
args.Handled = true;
};
uxFolderName.PreviewDrop += (sender, args) =>
{
if (args.Data.GetDataPresent(DataFormats.FileDrop))
{
string[] files = (string[])args.Data.GetData(DataFormats.FileDrop);
FolderName = (System.IO.Directory.Exists(files[0])) ? files[0] : System.IO.Path.GetDirectoryName(files[0]);
FolderSelected(this, new EventArgs());
}
};
}
/// <summary>
/// エンターキーが押された時の処理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void uxFolderName_PreviewKeyUp(object sender, KeyEventArgs e)
{
if(e.Key == Key.Enter)
{
FolderSelected(this, new EventArgs());
}
}
}
}
次の3つのバターンの時、FolderSelectedというイベントが発生するようにしています。
- テキスト部に手入力しエンターキーを押した時
- フォルダ選択ダイアログでフォルダを選択した時
- ドラッグ&ドロップでフォルダを入力した時
まとめ
今回はWindowsFormに標準搭載されているフォルダ選択ダイアログを使ったフォルダ選択ダイアログのユーザーコントロールを自作してみました。
WindowsForm と同じ感覚(イベントドリブン方式)で作っていますので、WindowsFormに慣れている方には理解しやすいかと思います。
これをベースに好きなように改造して使っていただければと思います。
コメント