Edited at

MVVMでファイルダイアログを使用する


やりたいこと

ViewModelからファイルダイアログを開く。


実装

ファイルダイアログを開くアクションを作成する。


アクション

using Microsoft.Win32;

using Prism.Interactivity.InteractionRequest;
using System;
using System.Linq;
using System.Windows;
using System.Windows.Interactivity;

namespace Sample {
public class PopupCommonDialogAction : TriggerAction<FrameworkElement> {
public static readonly DependencyProperty FileDialogTypeProperty
= DependencyProperty.Register(
nameof(FileDialogType),
typeof(Type),
typeof(PopupCommonDialogAction),
new PropertyMetadata(null));

public Type FileDialogType {
get { return (Type)GetValue(FileDialogTypeProperty); }
set { SetValue(FileDialogTypeProperty, value); }
}

protected override void Invoke(object parameter) {
var args = parameter as InteractionRequestedEventArgs;
if (args == null)
return;

var confirmation = args.Context as IConfirmation;
if (confirmation != null)
ShowDialog(confirmation);

args.Callback();
}

private void ShowDialog(IConfirmation confirmation) {
var dialog = (CommonDialog)Activator.CreateInstance(FileDialogType);
var confirmationProperties = confirmation.GetType().GetProperties();
var dialogProperties = dialog.GetType().GetProperties();

// ViewModelから渡された値をViewにセット
foreach (var prop in confirmationProperties) {
var value = prop.GetValue(confirmation, null);
if (value == null)
continue;

var dialogProp = dialogProperties
.FirstOrDefault(p => p.Name.Equals(prop.Name, StringComparison.OrdinalIgnoreCase));
if (dialogProp != null && dialogProp.CanWrite)
dialogProp.SetValue(dialog, value, null);
}

var ret = dialog.ShowDialog();

// Viewの値をViewModelに返す
foreach (var prop in dialogProperties) {
var ctxProp = confirmationProperties
.FirstOrDefault(p => p.Name.Equals(prop.Name, StringComparison.OrdinalIgnoreCase));
if (ctxProp != null && ctxProp.CanWrite)
ctxProp.SetValue(confirmation, prop.GetValue(dialog, null), null);
}

if (confirmation != null)
confirmation.Confirmed = ret == true;
}
}
}



通知クラス

using Prism.Interactivity.InteractionRequest;

namespace Sample {
public class FileDialogPropertyNotification : Confirmation {
//ファイルダイアログと同名のプロパティを定義する
public string FileName { get; set; }
public string Filter { get; set; }
//以下省略
}
}



使い方


XAML

<Window x:Class="Sample.MainView"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:prism="http://prismlibrary.com/"
xmlns:win32="clr-namespace:Microsoft.Win32;assembly=PresentationFramework"
xmlns:local="clr-namespace:Sample"
Title="MainView" Height="300" Width="300">
<i:Interaction.Triggers>
<!--セーブファイルダイアログ-->
<prism:InteractionRequestTrigger SourceObject="{Binding OpenSaveFileDialogRequest, Mode=OneWay}">
<local:PopupCommonDialogAction FileDialogType="{x:Type win32:SaveFileDialog}"/>
</prism:InteractionRequestTrigger>
<!--オープンファイルダイアログ-->
<prism:InteractionRequestTrigger SourceObject="{Binding OpenOpenFileDialogRequest, Mode=OneWay}">
<local:PopupCommonDialogAction FileDialogType="{x:Type win32:OpenFileDialog}"/>
</prism:InteractionRequestTrigger>
</i:Interaction.Triggers>
<Grid>
<TextBox />
</Grid>
</Window>


ViewModel

using Prism.Interactivity.InteractionRequest;

using System.Windows;

namespace Sample {
public class MainViewModel {
public InteractionRequest<FileDialogPropertyNotification> OpenOpenFileDialogRequest { get; }
= new InteractionRequest<FileDialogPropertyNotification>();

public InteractionRequest<FileDialogPropertyNotification> OpenSaveFileDialogRequest { get; }
= new InteractionRequest<FileDialogPropertyNotification>();

private string OpenOpenFileDialog(string title, string filter, string fileName = "") {
var notification = new FileDialogPropertyNotification() {
Title = title,
Filter = filter,
FileName = fileName
};
OpenOpenFileDialogRequest.Raise(notification);

return notification.Confirmed ? notification.FileName : string.Empty;
}

private string OpenSaveFileDialog(string title, string filter, string fileName = "") {
var notification = new FileDialogPropertyNotification() {
Title = title,
Filter = filter,
FileName = fileName
};
OpenSaveFileDialogRequest.Raise(notification);

return notification.Confirmed ? notification.FileName : string.Empty;
}
}
}