LoginSignup
5
10

More than 5 years have passed since last update.

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

Last updated at Posted at 2019-01-11

やりたいこと

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;
        }
    }
}
5
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
10