MessageBox MahApps с использованием MVVM

Простой вопрос для веселых мужчин MahApps. Я реализовал приложение, используя ваши великолепные элементы управления в стиле метро, ​​используя Caliburn.Micro для материала MVVM. Новые диалоги сообщений выглядят великолепно, но в настоящее время нет четкого способа запуска этих диалогов без написания собственной оболочки (против чего я не против). Однако было ли это сделано или я что-то упустил, чтобы без суеты вызывать окно сообщения из модели представления?

Спасибо за ваше время.


person MoonKnight    schedule 27.02.2014    source источник
comment
Вы используете последнюю версию MahApps.Metro?   -  person Guilherme Oliveira    schedule 28.02.2014
comment
Да, я использую последний исходный код.   -  person MoonKnight    schedule 03.03.2014
comment
Вы знаете, что они разработали диалоговое окно метро, ​​верно?   -  person Guilherme Oliveira    schedule 03.03.2014
comment
Да, но способ, которым это показано во всех примерах, заключается в использовании кода позади. Эти диалоги напрямую связаны с представлением, поэтому использование MVVM неясно...   -  person MoonKnight    schedule 03.03.2014
comment
Я только что ответил на ваш вопрос. У меня была такая же ситуация с моим проектом.   -  person Guilherme Oliveira    schedule 03.03.2014


Ответы (4)


Я создал оболочку для вызова диалогового окна сообщений MahApps.Metro, потому что у меня была такая же проблема с моим проектом MVVM. Мне пришлось создать список открытых окон, первое окно которого всегда будет моим MainWindow.

Вот мой 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);
}

Этот код можно использовать для отображения диалогов с результатом или без него. Вы можете заметить, что его возвращаемым значением является Task<MessageDialogResult>, поэтому, если вы хотите получить результат, вы можете сделать то же самое на своей ViewModel:

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

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

Кстати, если методу, вызывающему ShowMessage(), нужен результат, вы ОБЯЗАТЕЛЬНО ставите async в присваивании, иначе он не будет работать. (если вы хотите показать только диалоговое окно сообщения, в этом нет необходимости).

В моем проекте используется Framework 4.0, и я могу использовать только async/await из-за пакета, который мне пришлось установить из NuGet. Вы можете перейти по этой ссылке на документацию MSDN по этому пакету и скачать пакет здесь.

Я надеюсь, что это решило вашу проблему.

ИЗМЕНИТЬ:

Я реализовал метод на своем DialogService для открытия любых окон из любой ViewModel. Этот метод использует структуру Microsoft Unity для создания экземпляра моего объекта, а затем я вызываю Show(), чтобы открыть себя. Перед вызовом Show() я добавляю это окно в список.

Смотрите мой код:

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();
    }
}

Вот как я звоню из своей ViewModel:

_dialog.ShowView<MyView>();

Если у вас есть только одно окно во всем программном обеспечении, вы можете сохранить его ссылку и использовать его для отображения ShowMessageAsync() без необходимости создавать список только для использования первого. Как это:

var metroWindow = (Application.Current.MainWindow as MetroWindow);
person Guilherme Oliveira    schedule 03.03.2014
comment
Как получить список открытых представлений из модели представления, не нарушая MVVM? - person MoonKnight; 06.03.2014
comment
@Killercam Вы можете проверить мою правку. Я ответил вам там. - person Guilherme Oliveira; 06.03.2014
comment
Что ж, спасибо @Guilherme. Я уже создал эту службу сообщений. Но моя служба сообщений будет возвращать истину или ложь в зависимости от того, выбрал ли пользователь утвердительный/отрицательный вариант. Я тоже использую .net 4.0 и не хочу делиться dll mahapps в моем проекте моделей просмотра. Я не уверен, как заблокировать вызов, чтобы показать диалог в самом брокере обмена сообщениями, а затем отправить да/нет обратно в модель представления. Есть идеи? - person James; 10.03.2014
comment
Извините за спам. Создание независимого диалога всегда возможно, но я проверял, можно ли использовать для этой цели диалоги в стиле метро (из mahapps). Спасибо - person James; 10.03.2014
comment
@ Джеймс На самом деле, я не понял твоей идеи. Вы хотите показать диалоговое окно сообщения, но оно вернет да/нет в зависимости от утвердительного/отрицательного ответа, верно? Вы можете сделать эту проверку внутри метода, который вызывает диалог. Или вы можете попробовать использовать async/await, как я описал в своем ответе. Кстати, я бы не стал создавать независимый диалог в качестве диалога сообщений. - person Guilherme Oliveira; 10.03.2014
comment
Но как сделать так, чтобы метод брокера сообщений НЕ был aync. Я борюсь с этим. Я хочу, чтобы этот метод службы сообщений возвращал логическое значение. - person James; 10.03.2014
comment
@Джеймс Теперь я понял. Если бы я был на вашем месте, я бы вернул Утвердительное и Отрицательное вместо истинного и ложного, потому что для использования этого ShowMessageAsync метод должен быть асинхронным. Я спросил на GitHub об этой проблеме, вы можете прочитать здесь: github.com/MahApps/MahApps .Metro/issues/1092 - person Guilherme Oliveira; 10.03.2014
comment
Я не против вернуть даже messagedialog. Мне просто нужно поставить result==MessageDialog.Affirmative, чтобы вернуть true или false. Но я рад, что вы поняли мою проблему. Вся проблема в неизбежности асинхронного метода. Спасибо. - person James; 11.03.2014
comment
Я согласен Да/Нет является своего рода ограничительным. MessageDialog позволит вам вернуть больше параметров. Но, как я уже сказал, я не хочу, чтобы мои ViewModels касались dll MahApps. Но это не проблема, мой блок сообщений может преобразовать перечисление MessageDialog mahApps в другое перечисление-оболочку, которое понимают мои модели viewq. - person James; 11.03.2014
comment
@James Или у вас может быть два метода: один общедоступный (вы бы назвали его) и возвращает true/false, другой — частный и возвращает MessageDialogResult. Оба должны быть асинхронными, и вы должны поставить await перед вызовом обоих методов. Затем из вашей ViewModel вы вызываете первый, который возвращает true/false. Я думаю, это может сработать. Пожалуйста. - person Guilherme Oliveira; 11.03.2014
comment
Метод aysnc либо должен быть пустым, либо возвращать Task‹T›. Можете ли вы вставить сюда несколько строк кода о том, что вы думаете. Реализации не требуются, но, по крайней мере, код, отвечающий за async/await. Вот, например, интерфейс, о котором я говорю: открытый интерфейс IMessageService { bool ConfirmFromUser (строковый заголовок, строковое сообщение)} - person James; 11.03.2014
comment
@James Этот метод вызывает ShowMessage, который я указал выше в своем ответе: public async Task<bool> ConfirmFromUser(string header, string message) { var result = await ShowMessage(message, MessageDialogStyle.AffirmativeAndNegative); return result == MessageDialogResult.Affirmative; } Из ViewModel вы можете вызывать так: bool confirm = await _dialog.ConfirmFromUser("MY TITLE", "MY MESSAGE").ConfigureAwait(false); Я думаю, это может вам помочь. - person Guilherme Oliveira; 11.03.2014
comment
Откуда вы берете _openedViews? - person Oleksii; 12.06.2016
comment
@Oleksii Это частная собственность моего DialogService. - person Guilherme Oliveira; 13.06.2016

Начиная с версии 1.1.3-ALPHA* (которая станет версией 1.2.0) MahApps предоставляет помощник для запуска диалогов с виртуальной машины, который работает в многооконной настройке:

1) Используйте прикрепленное свойство в своем окне, чтобы зарегистрировать модель представления в подсистеме диалога.

Предполагая, что DataContext вашего представления установлен на модель представления, из которой вы хотите запустить диалоговое окно, добавьте эти атрибуты:

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

2) Захватите/вставьте DialogCoordinator:

new MainWindowViewModel(DialogCoordinator.Instance);

3) Покажите свой диалог из модели представления. Используйте «это» в качестве контекста, чтобы MahApps мог соединить вашу модель представления с правильным окном:

_dialogCoordinator.ShowMessageAsync(this, "Message from VM", "MVVM based dialogs!")
person James Willock    schedule 01.06.2015
comment
Вы хотите сказать 1.1.2.0 MahApps.Metro, потому что сейчас нет 1.2 согласно Фид Nuget MahApps.Metro - person Maverik; 20.10.2015
comment
1.2 ... в настоящее время он находится в альфа-версии, поэтому убедитесь, что вы включили предварительные версии в свой поиск nuget. - person James Willock; 20.10.2015
comment
Вы уверены, что это в ленте Nuget, а не в ленте myget? Из того, что я вижу, сейчас в фиде Nuget есть только MahApps.Metro 1.1.3-ALPHA198? В любом случае, я смог использовать ваш ответ даже в серии 1.1.3-ALPHA, и он работал как шарм, так что спасибо, что указали на это :) - person Maverik; 21.10.2015
comment
Ах, ладно, да, извините... 1.1.3-ALPHA* — это, в основном, то, что войдет в 1.2. Извинения. - person James Willock; 21.10.2015
comment
Без проблем. Возможно, измените свой ответ, чтобы люди, читающие это, не запутались, пока не будет выпущена версия 1.2.0? - person Maverik; 21.10.2015
comment
@JamesWillock У вас есть пример того, как зарегистрировать представление с помощью кода? - person Andres Ramos; 23.04.2016

Если у вас отображается только один экземпляр окна, вы можете попробовать что-то вроде этого:

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.");
        }
    }
}

И у вас должен быть способ идентифицировать каждое окно, чтобы вы могли отфильтровывать окна. Обратите внимание на импорт "Metro.Controls.Dialogs", который содержит расширения.

person Wickramaranga    schedule 07.02.2015

Я смог заставить это работать, сначала сделав родителя Dialog Conductor<Screen> . Затем в каком-то действии виртуальной машины для запуска диалогового окна я просто сделал следующее:

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);

}
person Purusartha    schedule 22.11.2019