2015-08-06 3 views
2

Привет, я хочу показать окно подтверждения при нажатии кнопки. Я пытаюсь разработать с использованием шаблона MVVM, я его достиг, но я не думаю, что Calling view in viewModel
- правильный способ сделать это. Я приложил код с этим, пожалуйста, пройти через это это правильный путь или нетОкно подтверждения В шаблоне проектирования MVVM

<Window x:Class="MessegeBox_Demo_2.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525"> 
     <Grid> 
      <Button Content="Ckick ME" HorizontalAlignment="Left" 
        Command="{Binding GetMessegeboxCommand}" 
        Margin="200,131,0,0" VerticalAlignment="Top" Width="75"/> 

     </Grid> 
    </Window> 

public class MainWindowViewModel : ViewModelBaseClass 
{ 
    private ICommand _getMessegeboxCommand; 
    public ICommand GetMessegeboxCommand 
    { 
     get 
     { 
      return _getMessegeboxCommand ?? (_getMessegeboxCommand = new MessegeBox_Demo_2.Command.realyCommand(() => ShowUsercontrol(), true)); 
     } 
    } 
    private void ShowUsercontrol() 
    { 
     MessegeBox_Demo_2.View.Window1 mbox = new View.Window1(); 
     mbox.ShowDialog(); 
    } 
} 
+2

Вы можете либо реализовать [диалоговое окно] (http://stackoverflow.com/a/28710441/220636), чтобы открыть диалоговое окно, либо использовать [сообщения] (http://stackoverflow.com/a/31161068/220636) для достижения чистого разделения проблем на MVVM-пути. – nabulke

+0

Здесь возникает несколько вопросов о том, как отображать новое представление (например, диалоговое окно) в ответ на событие ViewModel. То, что вы уже сделали, прекрасно, если оно работает. С точки зрения пуриста, вы можете взглянуть на использование DependencyProperties, чтобы предоставить View с механизмом обнаружения того, что ViewModel хочет получить окно подтверждения, не имея VeiwModel, чтобы вызвать прямо в View. –

ответ

3

Самый простой способ заключается в реализации dialogservice и использовать инъекции зависимостей, чтобы ввести услугу в к ViewModel. Хорошо иметь зависимость от интерфейса, но не иметь зависимости от конкретной реализации.
Ниже интерфейс я использую:

namespace DialogServiceInterfaceLibrary 
{ 
    public enum MessageBoxButton 
    { 
    // Summary: 
    //  The message box displays an OK button. 
    OK = 0, 
    // 
    // Summary: 
    //  The message box displays OK and Cancel buttons. 
    OKCancel = 1, 
    // 
    // Summary: 
    //  The message box displays Yes, No, and Cancel buttons. 
    YesNoCancel = 3, 
    // 
    // Summary: 
    //  The message box displays Yes and No buttons. 
    YesNo = 4, 
    } 

    public enum MessageBoxResult 
    { 
    // Summary: 
    //  The message box returns no result. 
    None = 0, 
    // 
    // Summary: 
    //  The result value of the message box is OK. 
    OK = 1, 
    // 
    // Summary: 
    //  The result value of the message box is Cancel. 
    Cancel = 2, 
    // 
    // Summary: 
    //  The result value of the message box is Yes. 
    Yes = 6, 
    // 
    // Summary: 
    //  The result value of the message box is No. 
    No = 7, 
    } 

    // Summary: 
    //  Specifies the icon that is displayed by a message box. 
    public enum MessageBoxIcon 
    { 
    // Summary: 
    //  No icon is displayed. 
    None = 0, 
    // 
    // Summary: 
    //  The message box contains a symbol consisting of white X in a circle with 
    //  a red background. 
    Error = 16, 
    // 
    // Summary: 
    //  The message box contains a symbol consisting of a white X in a circle with 
    //  a red background. 
    Hand = 16, 
    // 
    // Summary: 
    //  The message box contains a symbol consisting of white X in a circle with 
    //  a red background. 
    Stop = 16, 
    // 
    // Summary: 
    //  The message box contains a symbol consisting of a question mark in a circle. 
    Question = 32, 
    // 
    // Summary: 
    //  The message box contains a symbol consisting of an exclamation point in a 
    //  triangle with a yellow background. 
    Exclamation = 48, 
    // 
    // Summary: 
    //  The message box contains a symbol consisting of an exclamation point in a 
    //  triangle with a yellow background. 
    Warning = 48, 
    // 
    // Summary: 
    //  The message box contains a symbol consisting of a lowercase letter i in a 
    //  circle. 
    Information = 64, 
    // 
    // Summary: 
    //  The message box contains a symbol consisting of a lowercase letter i in a 
    //  circle. 
    Asterisk = 64, 
    } 

    public interface IDialogService 
    { 
     bool OpenFileDialog(bool checkFileExists,string Filter, out string FileName); 
     void OpenGenericDialog(object Context,IRegionManager RegionManager); 
    MessageBoxResult ShowMessageBox(string message, string caption, MessageBoxButton buttons, MessageBoxIcon icon); 
    } 

И реализация:

public class DialogService : IDialogService 
{ 
    public bool OpenFileDialog(bool checkFileExists, string Filter, out string FileName) 
    { 
     FileName = ""; 
     OpenFileDialog openFileDialog = new OpenFileDialog(); 
     openFileDialog.Multiselect = false; 
     //openFileDialog.Filter = "All Image Files | *.jpg;*.png | All files | *.*"; 
     openFileDialog.Filter = Filter; 
     openFileDialog.CheckFileExists = checkFileExists; 
     bool result = ((bool)openFileDialog.ShowDialog()); 
     if (result) 
     { 
      FileName = openFileDialog.FileName; 
     } 
     return result; 
    } 


    public void OpenGenericDialog(object Context,IRegionManager RegionManager) 
    { 
     GenericDialogWindow dlg = new GenericDialogWindow(Context,RegionManager); 
     dlg.Owner = System.Windows.Application.Current.MainWindow; 
     dlg.Show(); 
    } 

    public MessageBoxResult ShowMessageBox(string message, string caption, MessageBoxButton buttons, MessageBoxIcon icon) 
    { 
     return (DialogServiceInterfaceLibrary.MessageBoxResult)System.Windows.MessageBox.Show(message, caption, 
      (System.Windows.MessageBoxButton)buttons, 
      (System.Windows.MessageBoxImage)icon); 
    } 
} 

Затем впрыскивают IDialogservice в ViewModel. Интерфейс и конкретная реализация, как правило, в другой сборке

MainWindowViewModel(IDialogService dialogservice){ 
    _dialogservice = dialogservice; 
} 

private void ShowUsercontrol() 
{ 
    _dialogservice.ShowMessageBox(... //you get what i mean ;-) 
} 

dialogservice умеет открывать стандартные диалоги окна, как диалог открытия файла. Также можно использовать общую версию, но тогда вам нужно понять призму, которая немного сложнее. Prism также позволяет использовать запросы взаимодействия для связи с viewmodel до представления. Я предпочитаю этот способ работы в призме, но если вы не знаете, что призма забудет это замечание. Это, вероятно, слишком сложно для простого окна подтверждения. Так как простое диалоговое обслуживание, подобное этому, идеально подходит для простого окна подтверждения.

Имея зависимости, введенные через конструктор модели, перемещает вас уже в правильном направлении с помощью инверсии контейнера управления. И позволяет упростить модульное тестирование, потому что вы можете издеваться над инъецированными интерфейсами, чтобы проверить, правильно ли они вызваны и т. Д.

+0

Благодарим за помощь, мне нужно добавить любую внешнюю DLL для этого –

+0

Это зависит от ваших требований. Если вы хотите быть строгим, существует отдельная сборка для интерфейса и одна для реализации. Вам нужно обратиться к сборке интерфейса. И если вы не используете контейнер IOC, вам нужна ссылка на сборку имплантата. –

+0

не могли бы вы объяснить это два момента мне 1.RegionManager RegionManager 2. в котором namesapace GenericDialogWindow присутствует –

0

Вы не должны (никогда) вызывать методы пользовательского интерфейса внутри вашей модели просмотра, если вы хотите придерживаться шаблона MVVM.

Правильный способ открыть/закрыть окно из ViewModel - отправить сообщение в ваш просмотр с помощью Messenger MVVMLight или EventAggregator of Prism.

EventAggregator позволяет вашему ViewModel отправлять сообщения в список подписчиков. Когда вы подписываетесь на конкретное сообщение, вы присоединяете функцию для выполнения.

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

+0

Вам не нужен механизм событий просто для отображения диалогового окна подтверждения. Призма имеет для этого другой механизм: InteractionRequests. –

0

Я использовал MVVM Light для обмена сообщениями. Библиотека PRISM также обеспечивает хороший способ сделать это.

Для обработки взаимодействий, инициированных из модели представления и взаимодействий, созданных элементами управления, расположенными в представлении, библиотека Prism предоставляет InteractionRequests и InteractionRequestTriggers вместе с пользовательским действием InvokeCommandAction. InvokeCommandAction используется для подключения триггера, включающего события к команде WPF.

Создать свойство InteractionRequest в ViewModel:

public InteractionRequest<IConfirmation> ConfirmationRequest { get; private set; } 

Invoke взаимодействие, как это:

private void RaiseConfirmation() 
{ 
    this.ConfirmationRequest.Raise(
     new Confirmation { Content = "Confirmation Message", Title = "Confirmation" }, 
     c => { InteractionResultMessage = c.Confirmed ? "The user accepted." : "The user cancelled."; }); 
} 

Чтобы использовать взаимодействие запрашивает вам необходимо определить соответствующий InteractionRequestTrigger в XAML коде отображения вида:

<prism:InteractionRequestTrigger SourceObject="{Binding ConfirmationRequest, Mode=OneWay}"> 
    <prism:PopupWindowAction IsModal="True" CenterOverAssociatedObject="True"/> 
</prism:InteractionRequestTrigger> 

См. Interactivity QuickStart Using the Prism Library 5.0 for WPF

0
  • Подход DialogService более подходит в этом сценарии, чем механизм обмена сообщениями. Это более просты, легче отлаживать, легче писать, проще понять, вам не нужны сторонние рамки и т. Д.

  • СОВЕТ: Инжекция вместимости хороша, однако вам обычно требуется довольно много услуг, таких как NavigationService, DialogService, NotificationService и т. Д., И если вам нужно вставлять их во множество режимов просмотра, ctors становится большим, скучным, повторяя одни и те же инъекции и т. Д. И т. Д. Вместо инъекции зависимостей вы можете использовать любой другой «проверяемый» подход.

С DialogService будет одинаковой во всех ViewModels, вам не придется вводить его necesarilly каждого ViewModel, но вы можете использовать какое-то класс или локатор контекста приложения службы.

Пример класса ViewModelBase:

public class ViewModelBase : BindableBase 
{ 
     public virtual IDialogService DialogService 
     { 
     get { return AppContext.Current.DialogService; } 
     } 
} 

Пример конкретного ViewModel:

public class HomePageViewModel : ViewModelBase 
{ 
     ... 

     public void Cancel_CommandExecute() 
     { 
     var dlgResult = DialogService.ShowMessageBox("Do you really want to discard unsaved changes?", "Confirm Exit", DialogButtons.YesNo); 
     if (dlgResult != MessageBoxResult.Yes) return; 
     } 
} 

Диалог службы:

public interface IDialogService 
{ 
    MessageBoxResult ShowMessageBox(string messageBoxText, string caption = null, MessageBoxButton buttons = MessageBoxButton.OK, MessageBoxImage icon = MessageBoxImage.None, MessageBoxResult defaultResult = MessageBoxResult.None); 
} 

public class DialogService : IDialogService 
{ 
    public virtual MessageBoxResult ShowMessageBox(string messageBoxText, string caption = null, MessageBoxButton buttons = MessageBoxButton.OK, MessageBoxImage icon = MessageBoxImage.None, MessageBoxResult defaultResult = MessageBoxResult.None) 
    { 
     return MessageBox.Show(messageBoxText, caption, buttons, icon, defaultResult); 
    } 
} 

В своих тестах вы можете издеваться либо AppContext.Current, или вы можете override ViewModelBase.DialogService Недвижимость.

Возможно, это не самый чистый способ насмешки DialogService, но это прагматичный подход. Это делает ваш viewmodels более чистым, более читаемым и настраиваемым, так как вы не вводите и не храните DialogService экземпляр в каждой модели viewmodel. Ваши модели просмотра все еще развязаны из представлений, проверяемых, смешанных и т. Д.

0

Вы можете определить и заполнить код привязки позади. Поскольку код позади является частью представления, вызов Messagebox там не нарушает шаблон MVVM. Таким образом вы можете отобразить диалоговое окно подтверждения перед установкой значения привязки.

код вам нужно в коде за это:

public partial class MainWindow : Window 
{ 
    private DependencyProperty myDP; 

    public MainWindow() 
    { 
     ... 
     Binding myBinding = new Binding(); 
     myBinding.Path = new PropertyPath("myValue"); //myValue is a variable in ViewModel 
     myBinding.Source = DataContext; 
     myDP = DependencyProperty.Register("myValue", typeof(/*class or primitive type*/), typeof(MainWindow)); 
     BindingOperations.SetBinding(this, myDP, myBinding); 
     ... 
    } 

    private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     MessageBoxResult result = MessageBox.Show("Do you really want to do that?", "", MessageBoxButton.YesNo); 
     if (result == MessageBoxResult.Yes 
     { 
      SetValue(myDP, /*value*/); //this sets the Binding value. myValue in ViewModel is set 
     } 
    } 
} 

Для вызова Button_Click -метода, когда кнопка нажата, добавить

Click="Button_Click" 

в XAML-Definition вашей кнопки.

+0

@Downvoter, пожалуйста, объясните, что я сделал неправильно – Breeze

+0

1. Я не могу согласиться с утверждением: «ViewModel и View никогда не должны общаться ничем иным, как Bindings». Вам не следует создавать представления или доступ в режимах просмотра, но вы можете получить доступ к видам моделей из представлений. 2. Ваше приложение не позволяет проверить логику, связанную с диалоговыми окнами, например, показывает ли viewmodel диалог или как он реагирует на разные ответы – Liero

Смежные вопросы