46

ViewModelでMessageBox.Show()を呼び出すWPFアプリケーションがあります(ユーザーが本当に削除したいかどうかを確認するため)。これは実際には機能しますが、ViewModelはビューで何が起こるかを明示的に決定するべきではないため、MVVMの粒度に反します。

だから今、私はMVVMアプリケーションのオプションでMessageBox.Show()機能を最適に実装する方法を考えています:

  1. 「よろしいですか...?」というテキストのメッセージを送ることができます。XAMLの[はい]と[いいえ]の2つのボタンとともに、テンプレートにトリガーを作成して、AreYourSureDialogueBoxIsVisibleというViewModelPropertyに基づいて折りたたんだり表示したりします。次に、このダイアログボックスが必要な場合は、AreYourSureDialogueBoxIsVisibleを「true」に割り当てます。 "、およびViewModelに戻ってDelegateCommandを介して2つのボタンを処理します。

  2. また、XAMLのトリガーを使用してこれを処理し、[削除]ボタンを使用すると、メッセージとボタンが含まれるBorder要素が実際に表示され、[はい]ボタンが実際に削除されるようにすることもできます。

どちらのソリューションも、MessageBox.Show()を使用した数行のコードでは複雑すぎるようです。

MVVMアプリケーションにダイアログボックスをどのように正常に実装しましたか?

4

13 に答える 13

14

救助へのサービス。Onyx(免責事項、私は著者です)を使用すると、これは次のように簡単です。

public void Foo()
{
    IDisplayMessage dm = this.View.GetService<IDisplayMessage>();
    dm.Show("Hello, world!");
}

実行中のアプリケーションでは、これは間接的にMessageBox.Show( "Hello、world!")を呼び出します。テスト時に、IDisplayMessageサービスをモックしてViewModelに提供し、テスト中に実行したいことを実行できます。

于 2009-07-09T14:49:09.163 に答える
5

あなたが言及する2つのうち、私はオプション#2を好みます。ページの[削除]ボタンをクリックすると、[削除の確認]ダイアログが表示されます。「削除の確認ダイアログ」は実際に削除を開始します。

Karl ShifflettのWPF基幹業務のスライドとデモを確認しましたか?私は彼がこのようなことをしていることを知っています。どこを思い出そうか。

編集:デモ#11「MVVMでのデータ検証」(EditContactItemsControlSelectionViewModel.DeleteCommand)を確認してください。KarlはViewModalからポップアップを呼び出します(What !?:-)。私は実際にあなたのアイデアの方が好きです。ユニットテストが簡単なようです。

于 2009-07-08T13:27:57.973 に答える
5

彼のリンクがkaputである今、Dean Chalkの答えを拡張するには:

App.xaml.csファイルで、確認ダイアログをビューモデルに接続します。

protected override void OnStartup(StartupEventArgs e)
{
    base.OnStartup(e);
    var confirm = (Func<string, string, bool>)((msg, capt) => MessageBox.Show(msg, capt, MessageBoxButton.YesNo) == MessageBoxResult.Yes);
    var window = new MainWindowView();
    var viewModel = new MainWindowViewModel(confirm);
    window.DataContext = viewModel;
    ...
}

ビュー(MainWindowView.xaml)には、ViewModelのコマンドを呼び出すボタンがあります。

<Button Command="{Binding Path=DeleteCommand}" />

ビューモデル(MainWindowViewModel.cs)は、デリゲートコマンドを使用して、「よろしいですか?」を表示します。ダイアログを表示し、アクションを実行します。この例では、これSimpleCommandに似ていますが、ICommandのどの実装でも実行できます。

private readonly Func<string, string, bool> _confirm;

//constructor
public MainWindowViewModel(Func<string, string, bool> confirm)
{
    _confirm = confirm;
    ...
}

#region Delete Command
private SimpleCommand _deleteCommand;
public ICommand DeleteCommand
{
    get { return _deleteCommand ?? (_deleteCommand = new SimpleCommand(ExecuteDeleteCommand, CanExecuteDeleteCommand)); }
}

public bool CanExecuteDeleteCommand()
{
    //put your logic here whether to allow deletes
    return true;
}

public void ExecuteDeleteCommand()
{
    bool doDelete =_confirm("Are you sure?", "Confirm Delete");
    if (doDelete)
    {
        //delete from database
        ...
    }
}
#endregion
于 2015-07-17T08:12:19.860 に答える
4

VMに挿入されるインターフェイス(IMessageDisplayなど)を作成するだけで、MessageBox(ShowMessage()など)のようなメソッドがあります。これは、標準のメッセージボックス、またはよりWPF固有の何かを使用して実装できます(私はこれをPrajeeshのCodePlexで使用しています)。

そうすれば、すべてが分離され、テスト可能になります。

于 2010-07-16T08:38:43.460 に答える
3

ビューのコードビハインドで処理されるようなイベントを発生させるのはどうですか"MessageBoxRequested"(とにかく、ビューのみのコードなので、コードビハインドにこのコードを配置しても問題はありません)。

于 2012-09-26T18:36:01.187 に答える
3

他の誰かがまだ読んでいて満足していない場合に備えて:

「通知」タイプのMessageBoxを処理したかっただけです(つまり、私は気にしませんDialogResult)が、私が読んだほとんどのソリューションで私が抱えている問題は、それらが間接的にビューの実装を選択するように強制しているように見えることです(現在、私はを持っていますが、後でビューで直接非表示のパネルの表示をいじることにした場合、ViewModelに渡されMessageBox.Showたインターフェイスとうまくかみ合わないでしょう)。INotification

だから私は素早く汚いところに行きました:

ViewModelにはstring NotificationMessageプロパティがあり、変更はに通知されPropertyChangedます。

ビューはサブスクライブしPropertyChangedNotificationMessageプロパティが通過するのを確認すると、必要な処理を実行します。

これは、ビューにコードビハインドがあり、の名前PropertyChangedがハードコーディングされていることを意味しますが、とにかくXAMLではハードコーディングされます。そして、それは、可視性のコンバーターや、通知がまだ表示されているかどうかを示すプロパティなど、すべてのものを回避することを意味します。

(確かに、これは限られたユースケース(ファイアアンドフォーゲット)のためだけのものであり、どのように拡張したいかについてはあまり考えていません。)

于 2013-04-30T09:39:45.390 に答える
2

このトピックには、カスタムクラスの作成からサードパーティのライブラリの使用まで、さまざまな答えがあります。素敵なビジュアルを備えたクールなポップアップが必要な場合は、サードパーティのライブラリを使用すると思います。

ただし、WPFアプリにMicrosoftの通常のメッセージボックスを使用したい場合は、MVVM/単体テストに適した実装を次に示します。

最初は、メッセージボックスから継承してインターフェイスでラップするだけだと思っていましたが、メッセージボックスにパブリックコンストラクタがないためにできませんでした。そのため、「簡単な」解決策を次に示します。

Visual Studioでメッセージボックスを逆コンパイルすると、すべてのメソッドのオーバーロードが表示されます。必要なメソッドをチェックしてから、新しいクラスを作成してメソッドを追加し、インターフェイスとta-daでラップしました。これで、ninjectを使用してインターフェイスとクラスをバインドし、それを注入して、Moqを使用して単体テストなどを行うことができます。

インターフェイスを作成します(すべてを必要としないため、オーバーロードの一部のみを追加しました):

public interface IMessageBox
    {
        /// <summary>Displays a message box that has a message, title bar caption, and button; and that returns a result.</summary>          
        MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button);

        /// <summary>Displays a message box that has a message, title bar caption, button, and icon; and that returns a result.</summary>           
        MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon);

        /// <summary>Displays a message box that has a message and title bar caption; and that returns a result.</summary>            
        MessageBoxResult Show(string messageBoxText, string caption);
    }

次に、それを継承するクラスがあります。

public class MessageBoxHelper : IMessageBox
    {
        /// <summary>Displays a message box that has a message, title bar caption, button, and icon; and that returns a result.</summary>            
        public MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button,
            MessageBoxImage icon)
        {
            return MessageBox.Show(messageBoxText, caption, button, icon, MessageBoxResult.None,
                MessageBoxOptions.None);
        }

        /// <summary>Displays a message box that has a message, title bar caption, and button; and that returns a result.</summary>            
        public MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button)
        {
            return MessageBox.Show(messageBoxText, caption, button, MessageBoxImage.None, MessageBoxResult.None,
                MessageBoxOptions.None);
        }

        /// <summary>Displays a message box that has a message and title bar caption; and that returns a result.</summary>            
        public MessageBoxResult Show(string messageBoxText, string caption)
        {
            return MessageBox.Show(messageBoxText, caption, MessageBoxButton.OK, MessageBoxImage.None,
                MessageBoxResult.None, MessageBoxOptions.None);
        }

        /// <summary>Displays a message box that has a message and that returns a result.</summary>           
        public MessageBoxResult Show(string messageBoxText)
        {
            return MessageBox.Show(messageBoxText, string.Empty, MessageBoxButton.OK, MessageBoxImage.None,
                MessageBoxResult.None, MessageBoxOptions.None);
        }
    }

注入などの場合にこれを使用すると、ブームuには、トリックを実行する薄っぺらな抽象化があります...これは、使用する場所によっては問題ありません。私の場合は、いくつかのことを行うことだけを目的とした単純なアプリなので、ソリューションを設計することに意味はありません。これが誰かを助けることを願っています。

于 2018-09-17T15:18:33.180 に答える
1

純粋なMVVMソリューションで使用し、単体テスト機能を使用できるように、単純なMessageBoxラッパーコントロールを作成しました。詳細は私のブログhttp://geekswithblogs.net/mukapu/archive/2010/03/12/user-prompts-messagebox-with-mvvm.aspxにあります

ムカプ

于 2010-03-11T21:24:41.050 に答える
1

WPFおよびSilverlightメッセージボックス

サポートされているMVVM

http://slwpfmessagebox.codeplex.com/

于 2011-07-16T18:48:47.223 に答える
0

VMからスローするだけです。メッセージボックスをスローするためだけに、他の人のサービスを使用したり、自分のサービスを作成したりする必要はありません。

于 2009-07-16T16:09:16.007 に答える
0

ViewModelからのメッセージをリッスンするビヘイビアーを実装しました。Laurent Bugnionソリューションに基づいていますが、コードビハインドを使用せず、再利用性が高いため、よりエレガントだと思います。

こちらをチェックしてください

壊れたリンクのキャッシュ

于 2011-02-06T17:49:29.433 に答える
0

私は最近、ViewModelsのMessageBox.Showを完全にMVVMの苦情メッセージボックスメカニズムに置き換える必要があるというこの問題に遭遇しました。

これを実現するために、インタラクショントリガーを使用InteractionRequest<Notification>して、メッセージボックス用に独自のビューを作成しました。InteractionRequest<Confirmation>

私が実装したものはここに公開されています

于 2014-09-09T10:56:11.693 に答える
0

正常に動作しています[MVVM]

if (System.Windows.MessageBox.Show("Are you need to delete?", "", 
   System.Windows.MessageBoxButton.YesNo) == System.Windows.MessageBoxResult.Yes)
{
    // Do your action
}
于 2021-12-12T21:19:26.087 に答える