Как открыть новое окно с помощью MVVM Light Toolkit - PullRequest
46 голосов
/ 02 августа 2010

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

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

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

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

Ответы [ 6 ]

56 голосов
/ 02 августа 2010

Передача сообщения из 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();
        }
    }
}
4 голосов
/ 22 января 2011

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

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

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

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

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

3 голосов
/ 23 ноября 2010

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

Like This example

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

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

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

2 голосов
/ 18 мая 2011

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

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

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

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

2 голосов
/ 24 августа 2010

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

Похоже, что Bugnion предлагает, это view1 -> нажатие кнопки -> команда реле -> viewmodel1 -> сообщение -> view1 -> view1.cs -> открыть представление 2.

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

0 голосов
/ 24 октября 2014

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

  1. Создать 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. Создать базовую модель представления, унаследованную от 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 в базовой модели представления.

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

...