スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
当サイトは基本をすっ飛ばしてます。基本文法等は、@ITをどうぞ
カテゴリー: スポンサー広告

ファイルに保存したいのです。

 内部で処理をした後で、ファイルに保存させるとき、大抵はユーザーさんに保存先のフォルダとファイル名を入力(或いは選択)してもらう。Windows Forms同様、WPFにもこの保存用ダイアログというものが用意されている。
 ただし、このダイアログの実装で困ったのが、「ViewModel内でnewしてShowDialogしても良いのか?」という事だ。
var dialog = new Microsoft.Win32.SaveFileDialog();
dialog.ShowDialog();
あれ?これって画面だよな。てことは、インスタンスの生成や呼び出しは、「View」側にいるべきじゃね?そもそも、ShowDialogの第1引数に親ウィンドウ設定しないと、きっと碌なことにはならないし。
 でも、保存する為に選択したフォルダやらファイル名をViewModel側で受け取れないと、処理を続けられない。どうつなげばいいものか。で、悩んだ末に仕事において出した結論は、

Commandにすれば良いじゃない

だった。
「Commandである=ICommandインターフェイスを実装している」なんだから、コントロールにICommandを実装してバインディングさせてみよう!という事に至った。悪用ではない。多分。
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Threading;
using Microsoft.Win32;

namespace TawamureDays {

/// <summary>
/// ファイル保存用ダイアログ用コマンド
/// </summary>
public sealed class SaveFileDialogCommand : FrameworkElement, ICommand {

#region コンストラクタ

/// <summary>
/// staticコンストラクタ
/// </summary>
static SaveFileDialogCommand() {
//フォーカスは当たらない方が良い
FocusableProperty.OverrideMetadata(typeof(SaveFileDialogCommand),
new FrameworkPropertyMetadata(false));
//見えない方が良い
VisibilityProperty.OverrideMetadata(typeof(SaveFileDialogCommand),
new FrameworkPropertyMetadata(Visibility.Collapsed));
}

/// <summary>
/// コンストラクタ
/// </summary>
public SaveFileDialogCommand() {
return;
}

#endregion

#region ICommand メンバー

/// <summary>
/// 実行可否変更イベント
/// </summary>
public event System.EventHandler CanExecuteChanged;

/// <summary>
/// 指定されたパラメータと共にコマンドを実行します。<br/>
/// ファイル保存用ダイアログを開きます。<br/>
/// </summary>
/// <param name="parameter">コマンドパラメータ</param>
public void Execute(object parameter) {

//非同期実行下で呼ばれても良いようにする為、
//Invoke内でShowDialogを実行している。
var dlg = new SaveFileDialog();

var result =
(bool?)Application.Current.Dispatcher.Invoke(
(Func<SaveFileDialog, bool?>)(dialog => {
return dialog.ShowDialog(Window.GetWindow(this));
}), dlg);

if (result.GetValueOrDefault()) {

if (this.CallbackCommand != null &&
this.CallbackCommand.CanExecute(dlg.FileName)) {
this.CallbackCommand.Execute(dlg.FileName);
}
}

return;
}

/// <summary>
/// 現在の状態でコマンドが実行可能かどうかを判断します。<br/>
/// </summary>
/// <param name="parameter">コマンドパラメータ</param>
/// <returns>true:実行可能</returns>
public bool CanExecute(object parameter) {
return this.CanExecuteCommand;
}

#endregion

#region 依存関係プロパティ

/// <summary>
/// コマンド実行可能かどうかを取得/設定します。
/// </summary>
public bool CanExecuteCommand {
get {return (bool)GetValue(CanExecuteCommandProperty);}
set {SetValue(CanExecuteCommandProperty, value);}
}

/// <summary>コマンド実行可能かどうか</summary>
public static readonly DependencyProperty CanExecuteCommandProperty =
DependencyProperty.Register("CanExecuteCommand", typeof(bool),
typeof(SaveFileDialogCommand),
new UIPropertyMetadata(true));

/// <summary>
/// (保存先選択後)コールバック用のコマンドを取得/設定します。
/// </summary>
public ICommand CallbackCommand {
get {return (ICommand)GetValue(CallbackCommandProperty);}
set {SetValue(CallbackCommandProperty, value);}
}

/// <summary>(選択後)コールバック用のコマンド</summary>
public static readonly DependencyProperty CallbackCommandProperty =
DependencyProperty.Register("CallbackCommand", typeof(ICommand),
typeof(SaveFileDialogCommand), new UIPropertyMetadata(null));

#endregion

}
}
実行可否と保存後の処理をViewModelに任せるために、そのあたりはバインディングで呼び出せるようにする。XAML側の使い方はこんな感じ
<tw:SaveFileDialogCommand x:Name="SaveFileDialogCommand"
CallbackCommand="{Binding CallbackCommand"
CanExecuteCommand="{Binding CanExecuteSaveFile"
/>
<Button Content="保存"
Command="{Binding Path=., ElementName=SaveFileDialogCommand}"
/>

ボタンコントロールが持つCommandプロパティとバインディングさせ、ボタンを押した時に、SaveFileDialogCommandのExecuteメソッドが実行され、ファイル保存ダイアログが表示される…という流れになる。
保存先を指定して、「OK」を押したら、CallbackCommandが実行される。
上のサンプルは、あくまでサンプル用なので、本来は、拡張子だったり、初期のフォルダだったりをどこかで指定できたら、もっと便利になるかな。少なくとも、ViewModel側でnewしてみたり、ShowDialogを呼び出したりすることはない。
「はー、すっきりした。」というより、「今の所これしかないかな」という感じではあるんだけど。
スポンサーサイト
当サイトは基本をすっ飛ばしてます。基本文法等は、@ITをどうぞ
カテゴリー: WPF4 | コメント: 0 | トラックバック: 0


この記事へのコメント

コメントの投稿

非公開コメント


サイドバー背後固定表示サンプル

当ブログに書かれたソースコードは流用自由です。

バグ、スペルミス等はありうる事です。

ご利用の際は自己責任でお願いしますm(_ _)m

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。