C# 跨视图模型传递数据
我就是搞不懂。所以我会尽我所能描述我的问题 我正在使用MVVM模式构建应用程序。我使用viewmodelC# 跨视图模型传递数据,c#,wpf,mvvm,architecture,C#,Wpf,Mvvm,Architecture,我就是搞不懂。所以我会尽我所能描述我的问题 我正在使用MVVM模式构建应用程序。我使用viewmodelAAAViewModel的用户控件AAAViewModel来填充数据类CDATA类。我还有主窗口MainView和它的viewmodelMainViewModel。接下来,我有一个窗口DialogView和DialogViewModel 因此现在MainViewModel(具有自己的用户控件)创建了对话框viewmodel(具有另一个用户控件实例)。如何在这两个用户控件之间传输CDATA类中的
AAAViewModel
的用户控件AAAViewModel
来填充数据类CDATA类
。我还有主窗口MainView
和它的viewmodelMainViewModel
。接下来,我有一个窗口DialogView
和DialogViewModel
因此现在MainViewModel
(具有自己的用户控件)创建了对话框viewmodel
(具有另一个用户控件实例)。如何在这两个用户控件之间传输CDATA类中的数据?我试图在AAAViewModel
中创建属性,该属性将保存MainViewModel
或DialogViewModel
的实例,以便我可以向其传递数据,但由于无法将其作为依赖项属性,我被卡住了
我的目标是使用户控件可以在不同的视图中使用,这些视图可以在参考底图CDataClass
中具有不同的数据
只是想澄清一下。。。我将用户控件用作
,不知道如何在不同视图中的同一用户控件的两个不同实例之间共享数据。任何关于某种模式或方法的观点都将不胜感激
谢谢您的帮助。我认为将应用程序体系结构图表化为视图之间的关系并不理想;我认为更好的方法是将其视为viewmodels之间的一组关系,根据需要将视图挂在树上。当你这样想的时候,“数据是如何传递的”变得简单多了。视图只是viewmodel和用户之间的管道。你不会把房子设计成一套窗户和电话,然后再试图从中找出建筑平面图。你从房子的用途和人们将如何居住开始
所以这很简单:
某些ViewModel具有AAViewModel
属性。这些视图模型上可能有各种简单或复杂的视图;如果视图想让用户编辑viewmodel的AAViewModel
内容,那么它包括一个适当绑定到viewmodel的AAViewModel
的AAView
。您的MainViewModel
和DialogViewModel
都是大型复杂的交互式视图,希望有人能够编辑其虚拟机的AAViewModel
内容
如果MainViewModel
是DialogViewModel
的父对象,或者创建了一个DialogViewModel
的临时实例以放入一个模式对话框,那么MainViewModel
将显示该对话框,并查看dialogVM.AAVM.CData.IsDirty
以决定如何处理它。或者,在显示对话框之前,它可能会给dialogVM.AAVM
一个新的CDataClass
实例(可能是它自己实例的克隆),如果ShowModel()
返回true
,则它会使用dialogVM.AAVM.CData
关键是,一旦viewmodels驱动了一切,它们之间的通信就变得相对简单了。亲子关系很简单:父母给孩子东西,看孩子带回来什么。一个viewmodel可以订阅另一个viewmodel的PropertyChanged
事件;父视图模型可以监视其子视图模型;当孩子身上发生某些事情时,父母可以决定是否更新兄弟姐妹。一般来说,孩子们不应该知道任何关于他们父母的事情;这使得在不同的上下文中重用子视图模型变得更加容易。由家长决定如何处理这些信息
AAViewModel只知道有人递给他一份CDATA类的副本;他相应地更新了他的公共财产。然后其他人(可能是AAView
,但他不知道)通过设置他的属性给他一些更改;他相应地更新了他的CDataClass
实例。过了一会儿,他不知道,一个或另一个viewmodel来查看CDATA类
视图和视图模型之间的通信是通过绑定进行的
更新
事实证明,您正在视图中创建视图模型,因此您不知道父对象如何访问它们。现在您知道了为什么这样创建子视图模型不是一个好主意
以下是如何在我上面介绍的以viewmodel为中心的设计中实现子视图/视图模型:
首先,放弃在视图中创建子viewmodels所做的任何操作
其次,为子viewmodel类型创建一个DataTemplate
。这应该放在一个资源字典中,该字典被合并到App.xaml中的资源中,但是它非常简单,如果你懒散地将它粘贴到使用它的两个不同视图的resources
,它不会杀死你
我不知道您的名称空间声明是什么样子的。我将假设视图位于名为xmlns:view=“…”
的内容中,而视图模型位于名为xmlns:vm=“…”
的内容中
现在我们可以在对话框视图中显示AAAVM
:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ContentControl
Content="{Binding AAAVM}"
Grid.Row="0"
/>
<StackPanel Orientation="Vertical" Grid.Row="1">
<!-- Other stuff -->
</StackPanel>
</Grid>
请注意,下一个是view codebehind,而不是viewmodel
DialogView.xaml.cs
public static bool? ShowDialog(DialogViewModel dvm)
{
var vw = new DialogView() { DataContext = dvm };
return vw.ShowDialog();
}
public static bool? ShowDialog(CDataClass cdc)
{
var dlg = new DialogView();
dlg.ViewModel.AAAVVM.CDC = cdc;
return dlg.ShowDialog();
}
现在,您可以让对话框继续创建自己的viewmodel;在这种情况下,您可以将其作为公共财产,如下所示:
public DialogViewModel ViewModel => (DialogViewModel)DataContext;
还有一个ShowDialog方法,如下所示:
public DialogViewModel ViewModel => (DialogViewModel)DataContext;
DialogView.xaml.cs
public static bool? ShowDialog(DialogViewModel dvm)
{
var vw = new DialogView() { DataContext = dvm };
return vw.ShowDialog();
}
public static bool? ShowDialog(CDataClass cdc)
{
var dlg = new DialogView();
dlg.ViewModel.AAAVVM.CDC = cdc;
return dlg.ShowDialog();
}
然后父母可以像这样与它互动:
MainViewModel.cs
public CDataClass CDC { /* you know the drill */ }
public void ShowDialog()
{
var dvm = new DialogViewModel();
// Maybe this isn't what you want; I don't know what CDataClass does.
// But I'm assuming it has a copy constructor.
dvm.AAAVM.CDC = new CDataClass(this.CDC);
if (DialogView.ShowDialog(dvm).GetValueOrDefault())
{
CDC = dvm.CDC;
}
}
public void ShowDialog()
{
var cdcClone = new CDataClass(this.CDC);
if (DialogView.ShowDialog(cdcClone).GetValueOrDefault())
{
CDC = cdcClone;
}
}
干净整洁
如果该对话框不是模态对话框,请将对话框viewmodel设置为MainViewModel
的私有成员,并让MainViewModel
订阅对话框viewmodel上的事件,以了解该对话框正在执行的操作。每当用户更新对话框的CDataClass
副本时,对话框都会引发DataC