1

これが私の問題の流れです:

  1. ユーザーが「保存」ボタンをクリックする

  2. 宛先パスを選択するための「名前を付けて保存」ダイアログが表示されます

  3. 「保存」ボタンのクリックイベントのRelayCommandを実行する

現在、私は次のことについて何も考えていません。

  1. ダイアログを開き、EventToCommand バインディングで RelayCommand を実行する方法

  2. 「名前を付けて保存」ダイアログで選択したパスを RelayCommand に渡す方法

MVVM Light ライブラリを使用しています。

4

4 に答える 4

2

Dmitriy Reznikの回答はかなり良いと思いますが、別の解決策は、ボタンのコマンドを使用してViewModelでほとんどの作業を行うことです。これは MVVM パターンに厳密に従っているわけではありませんが、より簡単に実装できる可能性があります。

Button の Command を ViewModel の ICommand に設定します。ICommand は SaveFileDialog を起動し、ダイアログが閉じるとファイルをディスクに書き込みます。MVVM Light を使用しているので、RelayCommand を使用して ICommand を実装します。

Xaml:

<Button Command="{Binding SaveAsClickCmd}/>

コード:

public class MyViewModel
{
    public RelayCommand SaveAsClickCmd
    {
        get {
            return _saveAsClickCmd ?? (_saveAsClickCmd = new RelayCommand(() => {
                var dialog = new Microsoft.Win32.SaveFileDialog();
                if (dialog.ShowDialog() != true)
                    return;
                using (var stream = dialog.OpenFile()) {
                    //write out file to disk
                }
            }));
        }
    }

    private RelayCommand _saveAsClickCmd;
}
于 2012-04-10T21:03:04.630 に答える
1

MVVM Light ライブラリの DialogMessage クラスに基づいてクラスを作成しました (MVVM Light ライブラリを参照する必要があります)。

public class SaveFileDialogMessage : GenericMessage<string>
{
    /// <summary>
    /// Initializes a new instance of the <see cref="SaveFileDialogMessage" /> class.
    /// </summary>
    /// <param name="content">The content.</param>
    /// <param name="filter">The filter.</param>
    /// <param name="callback">The callback.</param>
    public SaveFileDialogMessage(string content, string filter, Action<bool?, string> callback)
        : base(content)
    {
        Filter = filter;
        Callback = callback;
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="SaveFileDialogMessage" /> class.
    /// </summary>
    /// <param name="sender">The sender.</param>
    /// <param name="content">The content.</param>
    /// <param name="filter">The filter.</param>
    /// <param name="callback">The callback.</param>
    public SaveFileDialogMessage(object sender, string content, string filter, Action<bool?, string> callback)
        : base(sender, content)
    {
        Filter = filter;
        Callback = callback;
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="SaveFileDialogMessage" /> class.
    /// </summary>
    /// <param name="sender">The sender.</param>
    /// <param name="target">The target.</param>
    /// <param name="content">The content.</param>
    /// <param name="filter">The filter.</param>
    /// <param name="callback">The callback.</param>
    public SaveFileDialogMessage(object sender, object target, string content, string filter, Action<bool?, string> callback)
        : base(sender, target, content)
    {
        Filter = filter;
        Callback = callback;
    }

    /// <summary>
    /// Gets a callback method that should be executed to deliver the result
    /// of the message box to the object that sent the message.
    /// </summary>
    public Action<bool?, string> Callback { get; private set; }

    /// <summary>
    /// Gets or sets the title.
    /// </summary>
    /// <value>
    /// The title.
    /// </value>
    public string Title { get; set; }

    /// <summary>
    /// Sets or gets the filter property.
    /// </summary>
    public string Filter { get; set; }

    /// <summary>
    /// Utility method, checks if the <see cref="Callback" /> property is
    /// null, and if it is not null, executes it.
    /// </summary>
    /// <param name="result">The result that must be passed
    /// to the dialog message caller.</param>
    /// <param name="fileName">Name of the file.</param>
    public void ProcessCallback(bool? result, string fileName)
    {
        if (Callback != null)
        {
            Callback(result, fileName);
        }
    }

次に、ViewModel には次のようなものがあります。

    var dialog = new SaveFileDialogMessage("Title", "XML Files" + "|" + ".xml", ProcessSaveFileDialog);
    Messenger.Default.Send(dialog);

    private void ProcessSaveFileDialog(bool? dialogResult, string fileName)
    {
            ..........
    }

そしてあなたのViewコンストラクターで:

    /// <summary>
    /// Initialize a new instance of the <see cref="MainView"/> class.
    /// </summary>
    public MainView()
    {
        InitializeComponent();
        Messenger.Default.Register<SaveFileDialogMessage>(this, msg =>
                                                                {
                                                                    var sfd = new SaveFileDialog { Filter = msg.Filter, Title = msg.Title };
                                                                    var result = sfd.ShowDialog();
                                                                    msg.ProcessCallback(result, sfd.FileName);
                                                                });
    }
于 2013-01-22T17:31:04.257 に答える
0

これが古いスレッドであることは承知していますが、(私のような) 初心者にとっては、適切な例を入手することが重要です。

個人的には、ViewModel でダイアログを宣言することは MVVM パターンに違反していると感じているため、上記の例はどれも好きではありません。IMHO、ViewModel は、ダイアログやメッセージ ボックスなどの UI 関連のコントロールを認識してはなりません。

グーグル中に、私はこれを見つけました: http://www.matt.digital/mvvm-light-communicating-across-layers-with-services/これは、MVVM のような方法でダイアログを表示する方法の完璧な例です。

于 2014-12-30T13:00:10.077 に答える
0

個人的には、viewModel ですべてを実行して MVVM の純度を追求するつもりはありません。コンポーネントがすぐに MVVM に対応していないことはそれほど珍しいことではなく、顧客が価値を失うまでの「追跡」には時間がかかる可能性があります。

とにかく、現在の質問には次のアプローチがあります。

  1. 文字列 (filePath) を返す OnSelectSavePath という viewModel でイベントを作成します。
  2. クリックするとviewModelがイベントを発生させます
  3. Page/UserControl/Window は、OpenFileDialog などを実行するメソッドを使用してイベントをサブスクライブします。
  4. Page/UserControl/Window は、そのメソッドから選択された文字列を返します
  5. ViewModel はイベントから文字列を受け取り、それを最大限に活用します。

このようにして、必要な機能を提供しながら、viewModel をプレゼンテーション レイヤーから正しく分離します (選択フォームの詳細を提供しません)。

別のアプローチは、MVVM をサポートするカスタム openFileDialog を定義することです。現在のviewModelをダイアログに渡すと、ダイアログはviewmodelのselectedPathプロパティを更新します。

さらに良いことに、codeBehing でそれを実行してから、selectedPath プロパティを使用して viewModel のメソッドを呼び出すことができます。これにより、すべての手間が省けます。

于 2012-04-09T18:47:55.973 に答える