【问题标题】:SimpleChildWindows binded to View Model简单的子窗口绑定到 Viewmodel
【发布时间】:2017-01-12 15:50:42
【问题描述】:

我正在使用 MVVM Light、MahApps 和 SimpleChildWindows。

我希望能够在模式弹出窗口中创建 CRUD 表单。

此 CRUD 表单必须绑定到它自己的 ViewModel 并由另一个 ViewModel 中的命令调用。

我无法使用 SimpleChildWindows 成功地做到这一点...

那么……有可能吗?

【问题讨论】:

    标签: c# wpf mvvm mvvm-light mahapps.metro


    【解决方案1】:

    我是如何利用依赖注入为自己解决类似问题的:

    我使用Unity 并注册了对“Func”的依赖:

    
    public partial class App
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
            IUnityContainer container = new UnityContainer();
            container.RegisterType<EntityCRUDWindowViewModel>();
            container.RegisterType<ConsumerViewModel>();
            container.RegisterInstance<Func<Entity, EntityCRUDWindow>>(entity =>  new EntityCRUDWindow(){DataContext=container.Resolve<EntityCRUDWindowViewModel>(new ParameterOverride("entity", new InjectionParameter<Entity>(entity))));
            /* whatever goes here */
        }
    }
    

    CRUD 窗口的 ViewModel 看起来像

    
    public class EntityCRUDWindowViewModel
    {
        private readonly Entity entity;
    
        public EntityCRUDWindowViewModel(Entity entity)
        {
            this.entity = entity;
        }
    }
    

    你可以得到窗口EntityCRUDWindow的实例并在ConsumerViewModel或任何其他ViewModel中使用它,只需在构造函数参数中声明

    
    public class ConsumerViewModel
    {
        public ConsumerViewModel(Func<Entity, EntityCRUDWindow> entityCrudWindowFactory)
        {
           this.WhateverCommand = new DelegateCommand(
               () =>
               {
                   Entity someEntity = null; //or whatever
                   entityCrudWindowFactory(someEntity).ShowDialog();
               });
        }
    
        public ICommand WhateverCommand { get; }
    }
    

    因此,您可以将所需的任何依赖项放入两个视图模型的构造函数参数中,只需记住 Entity entity 参数必须存在于 EntityCRUDWindowViewModel 中。

    【讨论】:

    • 抱歉,我看不出它对我有什么帮助...我想要一个模态 CRUD 对话框。您的代码允许我创建一个 CRUD ViewModel。
    • 这是一种使窗口可以从任何地方访问的方法。我的代码不创建视图模型,它自己创建视图(在本例中为窗口)
    • 我想我已经很好地解释了我想要什么,也许我的“编辑”会更好地解释。
    • 我明白了。是的,那是另一个故事。对不起;)你的主虚拟机中有一个 crudviewmodel 列表吗?
    • 我的主 VM 中有一个 ViewModel 列表,它们通过消息(MVVM Light Messenger)进行通信
    【解决方案2】:

    我可能会将 DataTemplate 添加到资源中,并且每当您将 Content 绑定到某个 CrudViewModelType 实例时都会呈现

    
    
        <Grid>
            <Grid.Resources>
                <DataTemplate DataType="{x:Type whateverNs:MyCrudViewModelType}">
                    <UserControl Content="{Binding}"/>
                </DataTemplate>
            </Grid.Resources>
            <ContentControl Content={Binding CurrentCrudViewModel}></ContentControl>
            <simpleChildWindow:ChildWindow IsOpen="{Binding OpenChildWindows}" Content="{Binding MyCrudViewModel}"/>
        </Grid>
    
    

    【讨论】:

      【解决方案3】:

      好吧,有时解决方案就在我的眼皮底下,但我很难看到它......

      所以这是我的解决方案:

       <Grid>
          <Grid >
              <UserControl Content="{Binding Path=CurrentViewModel}"/>
          </Grid>
          <simpleChildWindow:ChildWindow IsOpen="{Binding OpenChildWindows}"
                                         Title="{Binding TitleChildWindows}"
                                         Content="{Binding CurrentWindowsViewModel }"/>
      </Grid>
      

      CurrentWindowsViewModel 绑定到一个 UserControl,它完全适合我的 SimpleChildWindows 的 Content 属性。

      但是,我必须将所有 ChildWindows 属性绑定到“托管”我的子窗口(“标题”、“IsOpen”等)的 Viewmodel。

      所有 ChildWindows ViewModel 都继承自具有 Title 的类 Template(显然继承自 ViewModelBase)以及可能特定于 ChildWindows 的其他一些属性。

      我通过 MVVM light Messenger 进行通信,以通过名称告诉“主机”要显示哪个 ViewModel,然后读取其“标题”并通过“IsOpen”属性打开 Windows:

              private void ReceiveMessage(EnumViewModelNames viewName)
              {
              var selectedViewModel = ViewModelList.Where(x => x.ViewModelName == viewName).SingleOrDefault();
              if (selectedViewModel is TemplateWindowsViewModel)
              {
                  TitleChildWindows = (selectedViewModel as TemplateWindowsViewModel).Title;
                  OpenChildWindows = true;
                  CurrentWindowsViewModel = (selectedViewModel as TemplateWindowsViewModel);
              }
              else if (selectedViewModel != null)
              {
                  CurrentViewModel = selectedViewModel;
              }
              Messenger.Default.Unregister<EnumViewModelNames>(this, (action) => ReceiveMessage(action));
              }
      

      这样,我可以从“CurrentViewModel”或“MainViewModel”打开 childWindows。

      它工作得很好,视图只是一个标准的用户控件,绑定到 ViewModelLocator 中的 DataContext。

      对不起,Heorhiy Pavlovych,我看到你很努力,但我们误解了......

      【讨论】:

      • 你好 Speuline,这篇文章很旧,但对我来说它是新的 :) ,我有同样的问题,但我无法成功使其正常工作。你能不能给我一个你的例子工作的例子。最好的祝福。乔莉妮丝
      • 您好,您使用 SimpleChildWindows 库吗?
      • 您好 Speuline,是的,我使用 SimpleChildWindows 库。我是 WPF 的新手 :( ,请你帮帮我。谢谢。
      • 我不知道我可以添加什么...您只需将 SimpleChildWindows 的命名空间添加到将托管您 childWindows 的用户控件,然后您执行我在此答案中写的操作:直接绑定viewModel 的“打开”属性。当你想打开窗口时,你只需将 IsOpen 属性传递给 true(不要忘记 raisepropertyChange 或 INotifyPropertyChanged)。另外,不要忘记将 CurrentWindowsViewModel 属性分配给 childWindows 的 viewModel。如果您遇到问题,请给我一些代码,我会看看我能做什么。
      • 嗨,Speuline,我会再试一次,听从你的建议。我会给你我的反馈。谢谢
      猜你喜欢
      • 2016-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-05
      相关资源
      最近更新 更多