Как открыть новое окно с помощью MVVM Light Toolkit

Я использую MVVM Light toolkit в моем приложении WPF. Я хотел бы знать, что лучше всего подходит для открытия нового окна из существующего окна. У меня есть этот MainViewModel, который отвечает за MainWindow моего приложения. Теперь в MainView, при нажатии кнопки, я хотел бы открыть второе окно поверх него. У меня есть RelayCommmand связанный с Button Command. В методе RelayCommand я могу создать новый объект окна и просто вызвать Show(), что-то вроде этого:

var view2 = new view2()
view2.Show()

но я не думаю, что ViewModel должен нести ответственность за создание нового объекта view2. Я прочитал этот пост WPF MVVM Get Parent из VIEW MODEL, где Bugnion предложил передать сообщение в view1 из viewmodel1, а затем view1 должен создать новый view2. Но я не уверен, что он на самом деле означает, передав сообщение view1? Как обработать сообщение view1? В нем код позади или что?

С уважением, Набиль

Ответ 1

Передача сообщения из ViewModel1 в View1 означает использование возможностей обмена сообщениями в MVVM Light Toolkit.

Например, ваш ViewModel1 может иметь команду ShowView2Command, затем он отправит сообщение для отображения представления.

public class ViewModel1 : ViewModelBase
{
    public RelayCommand ShowView2Command { private set; get; }

    public ViewModel1() : base()
    {
        ShowView2Command = new RelayCommand(ShowView2CommandExecute);
    }

    public void ShowView2CommandExecute()
    {
        Messenger.Default.Send(new NotificationMessage("ShowView2"));
    }
}

View1 будет регистрироваться, чтобы получать сообщения в своем коде позади и отображать View2, когда он получает правильное сообщение.

public partial class View1 : UserControl
{
    public View1()
    {
        InitializeComponent();
        Messenger.Default.Register<NotificationMessage>(this, NotificationMessageReceived);
    }

    private void NotificationMessageReceived(NotificationMessage msg)
    {
        if (msg.Notification == "ShowView2")
        {
            var view2 = new view2();
            view2.Show();
        }
    }
}

Ответ 2

Почему вы идете по этому маршруту? Это просто. Если вы замените свою кнопку на toggleButton или на гиперссылку или на любое другое количество кнопочных элементов управления, вам не нужно обновлять свой "код позади" - это основной принцип шаблона MVVM. В вашем новом toggleButton (или что-то еще) вы все равно ввязываетесь в одну и ту же точную команду.

Например, я создаю проект для клиента, который хочет иметь 2 пользовательских интерфейса - один из них будет принципиально отличаться во всех отношениях, с точки зрения презентации. Горизонтальные вкладки против вертикального RadPanelBar (думаю, Аккордеон) для навигации. Оба эти представления могут указывать на один и тот же viewModel - когда пользователь нажимает вкладку "Заказ работы" в представлении 1, он запускает ту же самую "WorkOrderCommand", которая запускается в заголовке рабочего заказа на панели панели.

В модели с кодировкой кода вам нужно будет закодировать два отдельных события. Здесь вам нужно только ввести код.

Кроме того, он позволяет дизайнеру с помощью Blend создавать любой макет, который им нужен. Пока у них есть крючки (EventToCommand control) на месте, мне (как разработчику) все равно, чем выглядит конечный продукт.

Свободная связь невероятно мощная.

Ответ 3

Вы можете сделать так, как вам нужно создать некоторые события и зарегистрировать их в представлении и вызвать их в виде model.and открыть это всплывающее окно.

Как этот пример

public class Mainclass : MainView
{
    public delegate abc RegisterPopUp(abc A);
    public RegisterPopUp POpUpEvent ;

    public RelayCommand ShowCommand { private set; get; }  


    public void ShowCommand() 
    { 
        ShowCommand("Your parameter");
    } 
}

внутри представления MainView mn=new MainView();

Зарегистрируйте событие здесь, например thake mn.POpUpEvent +=, чем дважды нажмите кнопку вкладки

а во всплывающем методе регистров правильно введите код для открытия всплывающего окна.

Ответ 4

Если я не пропущу здесь смысла - если бы я использовал код позади, то почему бы прямо не реализовать событие button_click и открыть второе представление?

Что, по-видимому, предлагает Bugnion, это view1 → кнопка click → команда relay → viewmodel1 → message → view1 → view1.cs → open view 2.

Вы собираетесь жертвовать тестируемостью, написав код, поэтому зачем брать такой длинный маршрут?

Ответ 5

Вы можете абстрагировать специфические функции просмотра в сервисах, используя общий интерфейс. В слое представления вы можете предоставить конкретные экземпляры этих служб и построить модели представления с использованием контейнера IoC и метода впрыска зависимостей.

В вашем случае вы можете создать интерфейс IWindowManager или что-то подобное, у которого есть необходимый метод. Это можно применить к вашему слою представления. Недавно я написал небольшое сообщение в блоге, в котором показано, как абстрагироваться от поведения диалогового поведения вне модели. Подобный apporach можно использовать для любого связанного с пользовательским интерфейсом сервиса, такого как Навигация, MessageBoxes и т.д.

Эта ссылка может быть полезна для вас http://nileshgule.blogspot.com/2011/05/silverlight-use-dialogservice-to.html

Многие люди также используют подход для запуска событий из моделей просмотра, которые подписаны на файл view.cs, и оттуда выполняется MessageBox или любое другое действие, связанное с пользовательским интерфейсом. Мне лично нравится подход к инъекционным услугам, потому что тогда вы можете предоставить несколько реализаций одной и той же услуги. Простым примером может быть то, как навигацию обрабатывают в приложениях Silverlight и Windows Phone 7. Вы можете использовать одну и ту же модель представления, но вводить различные реализации службы навигации на основе типа приложения.

Ответ 6

Я нахожу лучший способ приблизиться к этому, открывает и закрывает окно из ViewModel. Как эта ссылка предлагает,

  • Создайте класс DialogCloser
    public static class DialogCloser
    {
        public static readonly DependencyProperty DialogResultProperty = DependencyProperty.RegisterAttached("DialogResult", typeof(bool?), typeof(DialogCloser), new PropertyMetadata(DialogResultChanged));

        private static void DialogResultChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var window = d as Window;
            if (window != null) window.Close();
        }

        public static void SetDialogResult(Window target, bool? value)
        {
            target.SetValue(DialogResultProperty, value);
        }
    }
  1. Создайте базовый ViewModel, наследующий от GalaSoft.MvvmLight.ViewModelBase, с дополнительными членами. После этого используйте эту модель представления как базу для других режимов просмотра.
    bool? _closeWindowFlag;
    public bool? CloseWindowFlag
    {
        get { return _closeWindowFlag; }
        set
        {
            _closeWindowFlag = value;
            RaisePropertyChanged("CloseWindowFlag");
        }
    }

    public virtual void CloseWindow(bool? result = true)
    {
        Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, 
        new Action(() =>
        {
            CloseWindowFlag = CloseWindowFlag == null ? true : !CloseWindowFlag;
        }));
    }
  1. В представлении привяжите свойство зависимостей DialogCloser.DialogResult с свойством CloseWindowFlag в базовой модели просмотра.

Затем вы можете открыть/закрыть/скрыть окно из режима просмотра.