【问题标题】:Show dialog with MVVM Light toolkit使用 MVVM Light 工具包显示对话框
【发布时间】:2011-08-04 09:45:49
【问题描述】:

我有一个 ViewModel 需要在单击按钮时显示模式窗口(使用 ShowDialog())。 ViewModel 捕获点击命令,但我不想在我的 ViewModel 中执行window.ShowDialog()。我知道 MVVM Light 中有一个DialogMessage,但它用于显示消息框,而不是 WPF 模式窗口。

关于如何做到这一点的任何想法?

【问题讨论】:

标签: mvvm dialog mvvm-light


【解决方案1】:

您应该使用Messenger 类。在View上注册一条消息显示窗口,当需要显示时调用Messenger类的Send方法。

你可以这样做:

    //do this in the code-behind file of your View
    Messenger.Default.Register<string>(this, ShowWindow);
    
    private void ShowWindow(string message)
    {
        // your logic here
    }
    
    // In the ViewModel
    Messenger.Default.Send(“Some text”);

【讨论】:

    【解决方案2】:

    这是我在 MVVM-Light Toolkit 中使用的自定义对话框。

    首先,在应用程序的某个位置定义这四个类。 MessageBase 类是工具包的一部分。

    public class ShowChildWindowMessage : MessageBase { }
    public class HideChildWindowMessage : MessageBase { }
    public class DisplaySomeContentMessage : MessageBase { }
    public class DisplaySomeOtherContentMessage : MessageBase { }
    

    其次,您需要一个“子”窗口控件。创建一个包含以下内容的 XAML 文件:

    <Window x:Class="ChildWindowView"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            DataContext="{Binding Path=ChildWindowBinding, Source={StaticResource Locator}}"
            Title="{Binding Path=CurrentContent.DisplayName}"
            MinWidth="300" MinHeight="125" SizeToContent="WidthAndHeight"
            ShowInTaskbar="False" WindowState="Normal" ResizeMode="NoResize"
            WindowStartupLocation="CenterOwner" SnapsToDevicePixels="True">
    
        <Grid>
            <ContentPresenter Content="{Binding Path=CurrentContent}" />
        </Grid>
    </Window>
    
    

    然后将以下内容添加到此 XAML 文件的代码隐藏中:

    public partial class ChildWindowView : Window
    {
        public ChildWindowView(Window owner)
        {
            InitializeComponent();
            Owner = owner;
    
            Closing += (s, e) => 
            {
                // window reused so just hide
                e.Cancel = true;
                Messenger.Default.Send(new HideChildWindowMessage());
            };
        }
    
    }
    

    第三,将以下内容添加到 MainWindow.xaml 文件的代码隐藏中:

    public partial class MainWindowView : Window
    {
        private ChildWindowView m_childWindowView;
    
        public MainWindowView()
        {
            InitializeComponent();
            Closing += (s, e) => ViewModelLocator.CleanUp();
            Loaded += (s, e) =>
            {
                m_childWindowView = new ChildWindowView(this);
            };
    
            Messenger.Default.Register<ShowChildWindowMessage>(this, (msg) => m_childWindowView.ShowDialog());
            Messenger.Default.Register<HideChildWindowMessage>(this, (msg) => m_childWindowView.Hide());
        }
    }
    

    四、定义如下视图模型:

    public class ChildWindowVM : ViewModelBase
    {
        private ViewModelBase m_currentContent;
        public ViewModelBase CurrentContent
        {
            get { return m_currentContent; }
            set
            {
                m_currentContent = value;
                RaisePropertyChanged("CurrentContent");
    
                if (m_currentContent != null)
                {
                    Messenger.Default.Send(new ShowChildWindowMessage());
                }
            }
        }
    
        public ChildWindowVM()
        {
            Messenger.Default.Register<DisplaySomeContentMessage>(this, (msg) => CurrentContent = ViewModelLocator.SomeContentVm);
            Messenger.Default.Register<DisplaySomeOtherContentMessage>(this, (msg) => CurrentContent = ViewModelLocator.SomeOtherContentVm);
        }
    }
    

    第五,您为要在自定义对话框中显示的内容创建 XAML 文件和视图模型。在这个例子中,我的内容视图模型被命名为 SomeContent 和 SomeOtherContent。当然,你可以用你想要的任何东西替换它们。

    最后,为了使其工作,您必须通过将以下内容添加到您的应用程序资源中,将您的内容视图模型绑定到它们各自的 XAML 文件:

    <DataTemplate DataType="{x:Type viewmodels:SomeContentVM}">
        <views:SomeContentView/>
    </DataTemplate>
    
    <DataTemplate DataType="{x:Type viewmodels:SomeOtherContentVM}">
        <views:SomeOtherContentView/>
    </DataTemplate>
    

    完成所有这些设置后,添加可在子窗口中显示的新内容(XAML 和视图模型)就很简单了。要显示内容,只需使用 Messenger 类调用适当的消息:

    Messenger.Default.Send(new DisplaySomeContentMessage ());
    

    如果我需要为您澄清其中的任何部分,请告诉我。

    【讨论】:

    • 但是如何用这种方法返回对话结果呢?
    • “对话结果”在 ChildWindowVM 中 CurrentContent 属性引用的视图模型中处理。例如,您的 SomeContentView.xaml 将具有绑定到 SomeContentVM 类中的某个 RelayCommand 的按钮。单击按钮时,相关命令将执行分配给它的方法。换句话说,它与 MessageBox 的对话框结果并不完全相同,因为 ChildWindow 视图和视图模型并不关心所显示内容的行为。它只是 CurrentContent 属性引用的真实视图和视图模型的窗口包装器。
    • 有趣!我决定在我的 MainWindow.xaml (Dictionary) 中有一个子窗口列表。在上述方法中,ViewModels 被创建了两次,因此另一种方法是通过将 DataContext="{Binding Content, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContentPresenter}}}" 添加到 DataTemplates来更紧密地耦合 ViewModels >
    • @sky-dev,ViewModel 是如何“创建两次”的?
    • bugged87 在这段代码中又过了几天,我认为你是对的。我的 ViewModel 被创建了两次,因为我一直在使用 View-first MVVM 模式,其中 ViewModel 是在 ChildWindow 的内容控件中第二次创建的。从那以后,我首先将东西更新为 ViewModel,而且我实际上更喜欢它。它似乎真的节省了创建新视图的开销,因为如果我选择的话,我可以在同一个 ResourceDictionary 中指定它们。我仍在使用您的 ChildWindow 的变体,它允许同时打开多个子窗口。
    【解决方案3】:

    对于所有想要一个非常简单的解决方案并且可以接受非 100%-clean-MVVM 的人:
    我想从我的主窗口打开一个连接对话框并执行以下操作

    首先我给我的 MainWindow 起了一个名字:

    <Window x:Name="MainWindow">
    

    然后我在 MainWindowViewModel 中创建了一个命令:

    public ICommand AddInterfaceCommand
    {
        get
        {
            return new RelayCommand<Window>((parentWindow) =>
            {
                var wizard = new ConnectionWizard();
                wizard.Owner = parentWindow;
                wizard.ShowDialog();
            }
        }
    }
    

    我将 MainWindow 上的 Button 绑定到 Command 并传递窗口本身(对话框的父窗口):

    <Button Command="{Binding AddInterfaceCommand}" CommandParameter="{Binding ElementName=MainWindow}">Add interface</Button>
    

    就是这样。

    唯一需要注意的是:从对话框的视图模型中获取返回值可能很困难。我不需要那个功能。

    【讨论】:

      【解决方案4】:

      您可以按如下方式定义接口及其实现。当然,对于依赖注入容器,你必须做这样的事情。

      NInjectKernel.Bind<IMessageBoxService>().To<MessageBoxService>();
      

      您的 ViewModel 将如下所示。

          private IMessageBoxService _MBService;
          public DropboxSettingsViewModel(IDropboxService dbService, IMessageBoxService mbService)
          {
              if (dbService == null)
                  throw new ArgumentNullException("IDropboxService is null");
      
              _DropboxService = dbService;
      
              if (mbService == null)
                  throw new ArgumentNullException("MessageBoxService is null");
      
              _MBService = mbService;
      
          }
      

      您的点击命令执行方法如下。

          private void ConfigureDropboxExecute(object obj)
          {
      
              _MBService.Show("Error Occured Authenticating dropbox", "Dropbox Authentication", MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK);
      
          }
      
      
      public interface  IMessageBoxService
      {
          MessageBoxResult Show(string messageBoxText);
          MessageBoxResult Show(string messageBoxText, string caption);
          MessageBoxResult Show(Window owner, string messageBoxText);
          MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button);
          MessageBoxResult Show(Window owner, string messageBoxText, string caption);
          MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon);
          MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button);
          MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult);
          MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon);
          MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult, MessageBoxOptions options);
          MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult);
          MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult, MessageBoxOptions options);
      }
      

      使用 System.Windows;

      public class MessageBoxService : IMessageBoxService
      {
          public MessageBoxResult Show(string messageBoxText)
          {
              return MessageBox.Show(messageBoxText);
          }
      
          public MessageBoxResult Show(Window owner, string messageBoxText)
          {
              return MessageBox.Show(owner, messageBoxText);
          }
      
          public MessageBoxResult Show(string messageBoxText, string caption)
          {
              return MessageBox.Show(messageBoxText, caption);
          }
      
          public MessageBoxResult Show(Window owner, string messageBoxText, string caption)
          {
              return MessageBox.Show(owner, messageBoxText, caption);
          }
      
          public MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button)
          {
              return MessageBox.Show(messageBoxText, caption, button);
          }
      
          public MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button)
          {
              return MessageBox.Show(owner, messageBoxText, caption, button);
          }
      
          public MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon)
          {
              return MessageBox.Show(messageBoxText, caption, button, icon);
          }
      
          public MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon)
          {
              return MessageBox.Show(owner, messageBoxText, caption, button, icon);
          }
      
          public MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult)
          {
              return MessageBox.Show(messageBoxText, caption, button, icon, defaultResult);
          }
      
          public MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult)
          {
              return MessageBox.Show(owner, messageBoxText, caption, button, icon, defaultResult);
          }
      
          public MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult, MessageBoxOptions options)
          {
              return MessageBox.Show(messageBoxText, caption, button, icon, defaultResult, options);
          }
      
          public MessageBoxResult Show(Window owner, string messageBoxText, string caption, MessageBoxButton button, MessageBoxImage icon, MessageBoxResult defaultResult, MessageBoxOptions options)
          {
              return MessageBox.Show(owner, messageBoxText, caption, button, icon, defaultResult, options);
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-03-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-11
        • 1970-01-01
        • 2012-01-26
        相关资源
        最近更新 更多