wpf 使用 MVVM 的 MahApps MessageBoxes

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22083213/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 11:02:57  来源:igfitidea点击:

MahApps MessageBoxes using MVVM

c#wpfmvvmcaliburn.micromahapps.metro

提问by MoonKnight

Simple question for the MahApps Merry Men. I have implemented an application using your great metro styled controls using Caliburn.Micro for the MVVM stuff. The new message dialogs look great, but currently there is not clear way of launching these dialogs with out writing my own wrapper (which I am not against). However, has this been done or is there something I missing so that I can invoke a message box from a view model without any fuss?

MahApps Merry Men 的简单问题。我已经使用 Caliburn.Micro 为 MVVM 内容使用您出色的 Metro 风格控件实现了一个应用程序。新的消息对话框看起来很棒,但目前没有明确的方法来启动这些对话框而不编写我自己的包装器(我不反对)。但是,这已经完成还是我遗漏了什么,以便我可以毫不费力地从视图模型中调用消息框?

Thanks for your time.

谢谢你的时间。

采纳答案by Guilherme Oliveira

I have created a wrapper to call the MahApps.Metro message dialog, cause I was having the same problem with my MVVM project. I had to create a list of opened windows, which the first window will always be my MainWindow.

我创建了一个包装器来调用 MahApps.Metro 消息对话框,因为我的 MVVM 项目遇到了同样的问题。我必须创建一个打开的窗口列表,第一个窗口将始终是我的 MainWindow。

Here's my DialogServicecode:

这是我的DialogService代码:

public async Task<MessageDialogResult> ShowMessage(string message, MessageDialogStyle dialogStyle)
{
    var metroWindow = (_openedViews.First() as MetroWindow);
    metroWindow.MetroDialogOptions.ColorScheme = MetroDialogColorScheme.Accented;

    return await metroWindow.ShowMessageAsync("MY TITLE", message, dialogStyle, metroWindow.MetroDialogOptions);
}

This code can be used to show dialogs with or without a result. You can notice that its return is a Task<MessageDialogResult>, so if you want to get the result, you can do just like that on your ViewModel:

此代码可用于显示有或没有结果的对话框。你可以注意到它的返回是 a Task<MessageDialogResult>,所以如果你想得到结果,你可以在你的 ViewModel 上这样做:

MessageDialogResult result = await _dialog.ShowMessage("SOME MESSAGE HERE", MessageDialogStyle.AffirmativeAndNegative).ConfigureAwait(false);

if (result == MessageDialogResult.Affirmative)
{
    //Do something
}

By the way, if the method that calls the ShowMessage()needs a result, you MUSTput asyncon the assignment, otherwise it won't work. (if you only want to show a message dialog, it's not necessary).

顺便说一句,如果调用该方法ShowMessage()需要一个结果,你必须async该分配,否则将无法正常工作。(如果您只想显示消息对话框,则没有必要)。

My project is using Framework 4.0, and I can only use async/awaitdue to the package I had to install from NuGet. You can acces this linkfor the MSDN documentation of this package, and you can download the package here.

我的项目使用的是 Framework 4.0,async/await由于必须从 NuGet 安装包,所以我只能使用。您可以访问此包的 MSDN 文档链接,您可以在此处下载该包。

I hope it has solved your problem.

我希望它已经解决了你的问题。

EDIT:

编辑:

I have implemented a method on my DialogServiceto open any windows from any ViewModel. This method uses Microsoft Unityframework to instantiate my object, and then I call Show()to open itself. Before a call Show(), I add this window on a list.

我已经实现了一种方法,DialogService可以从任何 ViewModel 打开任何窗口。这个方法使用Microsoft Unityframework来实例化我的对象,然后我调用Show()open自身。在通话之前Show(),我将此窗口添加到列表中。

See my code:

看我的代码:

public void ShowView<T>(params ParameterOverride[] parameter)
{
    var window = UnityServiceConfigurator.Instance.Container.Resolve<T>(parameter) as MetroWindow;

    if (window != null)
    {
        if (Application.Current.MainWindow != window)
        {
            window.Owner = Application.Current.MainWindow;
            var ownerMetroWindow = (window.Owner as MetroWindow);

            if (!ownerMetroWindow.IsOverlayVisible())
                ownerMetroWindow.ShowOverlayAsync();
        }

        if (!_openedViews.Contains(window))
            _openedViews.Add(window);

        window.Show();
    }
}

This is how I call from my ViewModel:

这是我从 ViewModel 调用的方式:

_dialog.ShowView<MyView>();

If you have only one window on your entire software, you can save its reference and use it to show the ShowMessageAsync()without needing to create a List only to use the First. Like this:

如果你的整个软件只有一个窗口,你可以保存它的引用并用它来显示ShowMessageAsync()而不需要创建一个列表只使用第一个。像这样:

var metroWindow = (Application.Current.MainWindow as MetroWindow);

回答by James Willock

As of 1.1.3-ALPHA* (to become 1.2.0) MahApps provides a helper to launch dialogs from a VM, which works in a multiple Window setup:

从 1.1.3-ALPHA*(成为 1.2.0)开始,MahApps 提供了一个从 VM 启动对话框的帮助程序,它在多窗口设置中工作:

1) Use an attached property in your Window to register your view model with the dialog sub-system.

1) 在您的 Window 中使用附加属性将您的视图模型注册到对话框子系统。

Assuming your View's DataContext is set to the view model from where you want to launch the dialog, add these attributes:

假设您的 View 的 DataContext 设置为您想要启动对话框的视图模型,请添加以下属性:

<Controls:MetroWindow 
    xmlns:Dialog="clr-namespace:MahApps.Metro.Controls.Dialogs;assembly=MahApps.Metro"
    Dialog:DialogParticipation.Register="{Binding}">

2) Grab/inject DialogCoordinator:

2) 抓取/注入 DialogCoordinator:

new MainWindowViewModel(DialogCoordinator.Instance);

3) Show your dialog from the view model. Use "this" as the context so MahApps can marry your view model to the correct window:

3)从视图模型中显示您的对话框。使用“this”作为上下文,以便 MahApps 可以将您的视图模型与正确的窗口结合起来:

_dialogCoordinator.ShowMessageAsync(this, "Message from VM", "MVVM based dialogs!")

回答by Wickramaranga

If you have only one instance of your window showing, you can try something like this:

如果您只显示一个窗口实例,您可以尝试以下操作:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Caliburn.Micro;
using MahApps.Metro.Controls;
using MahApps.Metro.Controls.Dialogs;

namespace Busyboy
{
    [Export(typeof(IShell))]
    class MainViewModel : PropertyChangedBase, IShell
    {
        public void StartPomodoro()
        {
            var mainview0 = System.Windows.Application.Current.Windows.OfType<MainView>().FirstOrDefault();
            mainview0.ShowInputAsync("New Pomodoro", "Enter a name for new pomodoro session.");
        }
    }
}

And, you should have a way of identifying each window so you can filter out windows. Please note the import "Metro.Controls.Dialogs" which contains the extensions.

而且,您应该有一种识别每个窗口的方法,以便您可以过滤掉窗口。请注意包含扩展的导入“Metro.Controls.Dialogs”。

回答by Purusartha

I was able to get this working by first making the Dialog parent a Conductor<Screen>. Then in some VM action to launch the Dialog, I simply did the below:

我能够通过首先将 Dialog 父项设为Conductor<Screen>. 然后在启动对话框的一些 VM 操作中,我简单地执行了以下操作:

public async Task LaunchDialog(MyDialogVM vm)
{
   var customDialog = new CustomDialog { Title = "Some Title" };
   var view = new MyDialogView{DataContext = vm};   // instance of the view user control
   customDialog.Content = view;
   // this registers the vm with CaliburnMicro, hence all life-cycle events are available
   ActivateItem(vm);    

   await _dialogCoordinator.ShowMetroDialogAsync(this, customDialog);

}