【问题标题】:Send parameter to ViewModel through IDialogService when open new window打开新窗口时通过 IDialogService 向 ViewModel 发送参数
【发布时间】:2016-04-17 06:17:17
【问题描述】:

我有PersonViewModelDepartmentViewModel 和他们的PersonViewDepartmentView

PersonViewModel 有一个空的构造函数,但是DepartmentViewModel 有一个参数:

public class DepartmentViewModel
{
    public DepartmentViewModel(ObservableCollection<Person> persons)
    {}
}

我使用以下服务打开新窗口:

public interface IDialogService<T>
{
   void Show(IUnityContainer unityContainer);
   void ShowDialog(IUnityContainer unityContainer);
}

public class DialogService<T> : IDialogService<T> where T : Window
{
   public void Show(IUnityContainer unityContainer)
   {            
     var container = unityContainer;
     container.Resolve<T>().Show();
   }

   public void ShowDialog(IUnityContainer unityContainer)
   {            
      var container = unityContainer;            
      container.Resolve<T>().ShowDialog();            
   }
}

上面的服务真的很好用。到目前为止,在我想将参数发送到 DepartmentViewModel 之前,一切正常。

我的App.xaml.cs 拥有在OnStartup() 方法中实例化视图模型的所有内容:

protected override void OnStartup(StartupEventArgs e)
{
   _container = new UnityContainer();
   _container.RegisterType<IViewMainWindowViewModel, MainWindow>();
   _container.RegisterType<IViewMainWindowViewModel, MainViewModel>();
   _container.RegisterType<IViewPersonViewModel, PersonView>();
   _container.RegisterType<IViewPersonViewModel, PersonViewModel>(new ContainerControlledLifetimeManager());
   _container.RegisterType<IViewDepartmentViewModel, DepartmentView>();
   _container.RegisterType<IViewDepartmentViewModel, DepartmentViewModel>(new ContainerControlledLifetimeManager());
   //types
   _container.RegisterType(typeof(IDialogService<>), typeof(DialogService<>));
   _container.Resolve<MainWindow>().Show();
}

我的问题是当我从PersonViewModel 打开新窗口时如何向DepartmentViewModel 发送参数?

我的代码从PersonViewModel打开新窗口:

private readonly IDialogService<DepartmentView> _dialogDepartmentView;

public void ContinueCommand_DoWork(object obj)
{
   //want to send "persons" to departmentViewModel
   ObservableCollection<Person> persons = new ObservableCollection<Person>();           
    // Open new dialog    
   _dialogDepartmentView.ShowDialog(_unityContainer);
}

当我通过IDialogService打开新窗口时,如何将ObservableCollection&lt;Person&gt; persons发送到DepartmentViewModel

【问题讨论】:

  • 啊。 ServiceLocator 代码中的反模式。话虽如此,您有多少个DepartmentViewModel 实例?这是您应该采用哪种解决方案的决定因素。
  • @code4life 只是 DepartmentViewModel 的一个实例。反模式意味着不好?
  • 老实说应该尽量不要使用它。
  • @code4life 但如何从 viewModel 打开新窗口?您能否提供一个链接以查看打开新窗口的正确方法。
  • @StepUp。有很多谷歌点击,stackoverflow 本身有很多 QA。他们中的许多人建议采用中介模式。其他人建议服务。其他、事件、命令等。我发现服务更自然。

标签: c# wpf mvvm


【解决方案1】:

也许你需要一个新的 Dialog/UIService。

这是我用来实现和你一样的效果的 UiService。我不使用任何 IoC 容器。 ViewLocator 是一个简单的类,具有从 Vm 类型到 View 类型的字典映射。不过,您可以将 ViewLocator 替换为您想要的任何“ServiceLocator”。

public interface IUiService {
    void Close();
    void Show<TVm>(TVm vm) where TVm : ViewModel;
    public T ShowDialog<T, TVm>(TVm vm) 
        where T : class
        where TVm : ViewModel, IDialogReturnVm<T>;
}

public class UiService : IUiService
{
    private readonly Window window;

    public UiService(Window window)
    {
        this.window = window;
    }

    public void Close()
    {
        this.window.Close();
    }

    public void Show<TVm>(TVm vm) where TVm : ViewModel
    {
        Type windowType = ViewLocator.GetViewType<TVm>()

        var wnd = (Window)Activator.CreateInstance(windowType);

        wnd.DataContext = vm;
        wnd.Owner = Application.Current.MainWindow;
        vm.Init(new UiService(wnd));
        wnd.Show();
    }

    public T ShowDialog<T, TVm>(TVm vm) 
        where T : class  //T is the type of imformation which the Vm will "return" when it's window is closed.
        where TVm : ViewModel, IDialogReturnVm<T>
    {
        Type windowType = ViewLocator.GetViewType<TVm>()

        var wnd = (Window)Activator.CreateInstance(windowType);

        wnd.DataContext = vm;
        wnd.Owner = Application.Current.MainWindow;
        vm.Init(new UiService(wnd));
        wnd.ShowDialog();
        return vm.ReturnInfo;
    }
}

我所有的虚拟机都有一个 IUiService 属性,当我调用它的 Init 方法时会设置它。

在 AppStartup 中,当我想打开我的第一个窗口时,我会这样做:

Type windowType = ViewLocator.GetViewType<MainVm>()

var wnd = (Window)Activator.CreateInstance(windowType);

wnd.DataContext = new MainVm();
vm.Init(new UiService(wnd));
wnd.Show();

与我在UiService.Show 中所做的基本相同。

因此,当您想从另一个 ViewModel Show 一个 ViewModel 时,您调用 this.UiService.Show(new YourVm(parameters..));

IUiService.Show 然后将使用 ViewLocator 确定 VM 的窗口类型并创建一个新窗口。它还使用该窗口为新 VM 分配 IUiService。

IDialogReturnVm&lt;T&gt; 是一个具有单个属性 T ReturnInfo{get; private set;} 的接口,您可以在 Vm 中设置该属性。

这使 View 和 ViewModel 很好地解耦,同时仍然允许您将参数传递给 ViewModel。我什至将我的 ViewModel 放在不同的程序集中。 IUiService 在该程序集中定义,实现:UiService 在主程序集中定义。

【讨论】:

    猜你喜欢
    • 2013-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-05
    • 2020-11-08
    相关资源
    最近更新 更多