趣味や仕事に活かせるようなプログラムを作ろうとすると、必ずと言って良いほどファイルを選択する機能が必要になります。
幸いなことにWPFでもファイル選択ダイアログは標準で備わっていますので、今回はそれを使った「ファイル選択ダイアログ」のユーザーコントロールを作ってみました。
ファイル選択ダイアログの概要
見た目は前回作ったフォルダ選択ダイアログと同じです。

ファイル選択ダイアログは、読み込むためのファイルを選択(指定)するケースと、保存したいファイル名を選択(指定)するケースの2通りがあります。
このため、ダイアログも2通り用意されていますが、読み込むか保存するかの違いを除けば、ほぼ必要な機能は共通しています。
そこで、今回作成するユーザーコントロールは、読み込みと保存を兼用する形にしました。
機能としては次の通りです。
- ダイアログの動作モード(ファイル読み込み用、ファイル保存用)の指定
- テキスト部にファイル名を直接入力
- ファイル選択ダイアログの表示とファイルの選択
- テキスト部にファイルをドラッグ&ドロップで入力
- ファイル名が入力された時のイベント発生
動作モードがファイル読み込み用の場合、次のダイアログが表示されます。

動作モードがファイル保存用の場合、次のダイアログが表示されます。

ダウンロード先
今回のソースコードのダウンロード先は次の通りです。
デモプログラムに張り付けていますので、すぐに動作確認が出来る様になっています。
デモプログラムの仕様については、こちら をご参照ください。
ソースコード
では、ソースコードを見ていきましょう。
まずはXamlのソースコードです。
<UserControl x:Class="CommonUserControl.FileSelectControl"
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="uxFileName" PreviewKeyUp="uxFileName_PreviewKeyUp"/>
<Button x:Name="uxOpenDialog" Grid.Column="1" Background="{x:Null}" BorderThickness="0" HorizontalAlignment="Right" Margin="0,3,1,1" HorizontalContentAlignment="Center" Click="uxOpenDialog_Click">
<Image Source="Images/FolderOpen_exp_16x.png" />
</Button>
</Grid>
</UserControl>
次にC#のソースコードです。
using Microsoft.Win32;
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>
/// FileSelectControl.xaml の相互作用ロジック
/// </summary>
public partial class FileSelectControl : UserControl
{
/// <summary>
/// ファイル選択完了時のイベント定義
/// </summary>
public event EventHandler<EventArgs> FileSelected = delegate { };
/// <summary>
/// ファイル名
/// </summary>
public string FileName { get { return uxFileName.Text; } set { uxFileName.Text = value; } }
/// <summary>
/// フィルター
/// </summary>
public string Filter { get; set; }
/// <summary>
/// ダイアログモード(オープン/保存)
/// </summary>
public FileSelectDialogType DialogType { get; set; } = FileSelectDialogType.Open;
/// <summary>
/// コンストラクタ
/// </summary>
public FileSelectControl()
{
InitializeComponent();
DragDrop();
}
/// <summary>
/// フォルダアイコンクリック時の処理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void uxOpenDialog_Click(object sender, RoutedEventArgs e)
{
// FileSelectDialogTypeの値によってファイルオープン/保存ダイアログを切り分けてインスタンスを生成
var dlg = (DialogType == FileSelectDialogType.Open) ? (FileDialog)new OpenFileDialog() : (FileDialog)new SaveFileDialog();
dlg.FileName = FileName;
dlg.Filter = Filter;
// ダイアログを表示
if ((bool)dlg.ShowDialog())
{
FileName = dlg.FileName;
FileSelected(this, new EventArgs());
}
}
/// <summary>
/// ドラッグ&ドロップ処理
/// </summary>
private void DragDrop()
{
//ドラッグ&ドロップの処理
uxFileName.PreviewDragOver += (sender, args) =>
{
args.Effects = (args.Data.GetDataPresent(DataFormats.FileDrop) ? DragDropEffects.Copy : DragDropEffects.None);
//コントロールの種類によって、下記の記述が必要(PreviewDropが効かない場合がある) なので、念のため
args.Handled = true;
};
uxFileName.PreviewDrop += (sender, args) =>
{
if (args.Data.GetDataPresent(DataFormats.FileDrop))
{
string[] files = (string[])args.Data.GetData(DataFormats.FileDrop);
FileName = (System.IO.Directory.Exists(files[0])) ? files[0] : System.IO.Path.GetDirectoryName(files[0]);
FileSelected(this, new EventArgs());
}
};
}
/// <summary>
/// エンターキーが押された時の処理
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void uxFileName_PreviewKeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
FileSelected(this, new EventArgs());
}
}
}
//ダイアログ動作モード
public enum FileSelectDialogType
{
Open,Save
}
}
使い方
使用可能なプロパティとイベントは次の通りです。
| カテゴリ | 名前 | 説明 |
|---|---|---|
| プロパティ | FileName | 選択したファイル名 |
| プロパティ | Filter | 対象ファイルの拡張子を絞り込むフィルタ |
| プロパティ | DialogType | ダイアログモード FileSelectDialogType.Open 読み込み用 FileSelectDialogType.Save 保存用 |
| イベント | FileSelected | ドラッグ&ドロップ、ダイアログ選択、 手入力でファイルが選択された時に発行されるイベント |
Filterプロパティ
ダイアログを表示する際、ダイアログ内で特定の拡張子をフィルタリングするためのものです。
"説明1|ワイルドカード1|説明2|ワイルドカード2|・・・" という風に記述します。
例えば、"CSV/TSV|*.csv;*.tsv|全てファイル|*.*" と記述すると、
- 拡張子がcsvとtsvのファイルのみの
- 全てのファイル
ダイアログで切り替えて選択できるようになります。

DialogTypeプロパティ
ファイル選択ダイアログをファイル読み込み用で使うか、ファイル保存用で使うかはDialogTypeプロパティで指定します。
Xamlで指定する場合
ファイル読み込み用で使う場合
<CommonUserControl:FileSelectControl DialogType="Open"/>
ファイル保存用で使う場合
<CommonUserControl:FileSelectControl DialogType="Save" />
コードで指定する場合
ファイル読み込み用で使う場合
uxFileName.DialogType = CommonUserControl.FileSelectDialogType.Open;
ファイル保存用で使う場合
uxFileName.DialogType = CommonUserControl.FileSelectDialogType.Save;
FileSelectedイベント
テキスト部に任意のファイルをドラッグ&ドロップするか、ダイアログでファイルを選択するか、ファイル名を手入力してEnterキーを押したタイミングでイベントが発生します。
もし、ファイルを選択した瞬間にファイルを読み込む等の処理を行わせたい場合は、このイベントハンドラを記述して下さい。
まとめ
今回はファイル選択ダイアログを使ったユーザーコントロールを作りました。
ちょっとした機能ですが、毎回ゼロから作ったり別のソースからコピーするのは面倒ですので、ユーザーコントロールにしておくと便利です。
フォルダ選択ダイアログの場合はWindowsForm の参照設定が必要でしたが、ファイル選択ダイアログはWPFに標準装備されているのでお手軽です。
色々とカスタマイズしてお役立ていただければ幸いです。
コメント