从 MainWindow 访问 UserControl 中的属性 (WPF/MVVM)
Accesing properties in a UserControl from the MainWindow (WPF/MVVM)
我有一个小问题,我正在寻找实现它的正确方法。
我有一个 MainWindow 和一个 UserControl 来显示一些结果,在 MainWindow 中我有一个按钮 "load" 来加载一些数据,UserControl 应该显示它们。
我不确定在 WPF 和 MVVM 中执行此操作的正确方法是什么:
我应该将 MainWindowModel 传递给 UserControlModel 吗?;
我应该将 UserControlModel 传递给 MainWindowModel 吗?;
我是否应该公开 属性 我需要在我的 UserControl 中填充为 DependencyProperty,然后在 MainWindow 上填充它?
如有任何建议,我们将不胜感激。谢谢!
编辑 1:
这就是我调用 UserControl 的方式:
<TabControl Grid.Row="1"
Grid.RowSpan="2"
Grid.Column="0"
VerticalAlignment="Stretch">
<!--Result View-->
<TabItem Header="{Binding TabImportHeader}">
<results:ResultView/>
</TabItem>
<!--Configuration Tab-->
<TabItem Header="{Binding TabConfigurationHeader}">
<configuration:ConfigurationView />
</TabItem>
</TabControl>
出现问题的我的 UserControl 是 ResultView
MainWindowVMInstance.UserControlVMInstance.Property
UserControl
在你的 MainWindow
里面。
因此你的 MainWindow
有你的 UserControlVM
的 属性(/实例)。
注意:如果您还需要在 UserControlVM
中引用 MainWindowVM
,请将其传递给构造函数并将其存储为 属性。
在 xaml 中看起来像这样(在 MainWindow.xaml
中):
<ContentControl Content="{Binding UserControlVMInstance}"/>
别忘了 DataTemplate
:
<DataTemplate DataType="{x:Type vm:UserControlVM}">
<view:UserControlView/>
</DataTemplate>
问题更新后编辑:
这是一个示例,其中包含您的部分代码,用于演示 WPF 和 MVVM 的实际应用。您只需在 UserControl.Resources
中定义 DataTemplate
,然后通过 Binding
为 ContentControl
提供 UserControlVM
的一个实例。 WPF 知道此类型有一个 DataTemplate
,并将在 ContentControl
所在的位置添加一个 UserControlView
的实例。
<MainWindow>
<MainWindow.Resources>
<DataTemplate DataType="{x:Type vm:UserControlVM}">
<view:UserControlView/>
</DataTemplate>
</MainWindow.Resources>
<!-- Your TabControl -->
<TabControl>
<!--Result View-->
<TabItem Header="{Binding TabImportHeader}">
<ContentControl Content="{Binding TabImportCONTENT}"/>
</TabItem>
</TabControl>
</MainWindow>
Microsoft WPF 控件是使用 DependencyProperties 构建的
DependencyProperty 支持以下功能,在引入特定于控件的视图模型时您将失去这些功能:
DP可以在样式/触发器中设置(样式和模板很重要,开发人员经常希望重用控件的功能,但完全改变外观)
DP可以通过数据绑定设置(包括2个控件之间的交叉绑定)
DP可以从元素树中的父元素自动继承它的值
DP可以动画
在 ViewModel 之间共享资源是一种常见的情况,但是如果它确实成为问题,它通常是架构中出现问题或缺乏问题的一个很好的指标。
最简单的解决方案是让 UserControlVM
持有对 MainWidowVM
的引用并订阅某个事件,该事件由接口通过 Command
调用。然而,声明功能的 ViewModels
之间的交叉引用可能会变得非常混乱,交叉引用和循环引用最终会阻止 GarbageCollection
正确完成其工作,从而导致不必要的内存泄漏。
您还可以让您的 MainWindowVM
保留对每个其他 ViewModel
的引用,以通过至少集中交叉引用来提供集中的通信点。
下一个最简单的解决方案是使用 weak event binding 实现类似外部消息传递系统的东西。这摆脱了其他对象中对象的固定引用,但代价是性能极其沉重。如果您正在开发的应用程序具有例如包含 select 元素的主列表和不同 windows 中的许多模块化详细列表,这可能是可行的 - 来自 1 个主端的单向通信具有不频繁的更改和异步许多细节端的实现。对于您的目的,这应该没问题,如果这些事件将自动触发,但我建议完全采用不同的路由器。
上面列出的问题就是为什么MVVM不仅有Model
、ViewModel
和View
而且通常还用Services
来封装共享逻辑and/or 数据(资源)从 ViewModels
转移到有效的共享资源中。
您的 ViewModel(例如,在 LocalizationService
的情况下可能还有视图)将保存对服务的引用,并且通常都指向该服务的单个实例。这也消除了不需要的交叉引用,并允许正确绑定和正确(取消)订阅事件,而不会受到弱绑定的性能影响。
使用 Services
而不是交叉引用 ViewModels
的另一个好处是,它确实让您有机会实际遵循 SOLID principles of object-oriented programming 并在其所属的位置拥有逻辑,而无需重复。
之后可以使用 IoC-Container 在运行时正确地注入引用和依赖项,但是这会带来隐藏依赖项的风险以及项目设置、文档等方面的大量准备时间.如果第一次做的不对and/or。我个人不会走这条路,除非团队中的每个成员都真正知道他们在做什么。
我有一个小问题,我正在寻找实现它的正确方法。
我有一个 MainWindow 和一个 UserControl 来显示一些结果,在 MainWindow 中我有一个按钮 "load" 来加载一些数据,UserControl 应该显示它们。
我不确定在 WPF 和 MVVM 中执行此操作的正确方法是什么:
我应该将 MainWindowModel 传递给 UserControlModel 吗?;
我应该将 UserControlModel 传递给 MainWindowModel 吗?;
我是否应该公开 属性 我需要在我的 UserControl 中填充为 DependencyProperty,然后在 MainWindow 上填充它?
如有任何建议,我们将不胜感激。谢谢!
编辑 1: 这就是我调用 UserControl 的方式:
<TabControl Grid.Row="1"
Grid.RowSpan="2"
Grid.Column="0"
VerticalAlignment="Stretch">
<!--Result View-->
<TabItem Header="{Binding TabImportHeader}">
<results:ResultView/>
</TabItem>
<!--Configuration Tab-->
<TabItem Header="{Binding TabConfigurationHeader}">
<configuration:ConfigurationView />
</TabItem>
</TabControl>
出现问题的我的 UserControl 是 ResultView
MainWindowVMInstance.UserControlVMInstance.Property
UserControl
在你的 MainWindow
里面。
因此你的 MainWindow
有你的 UserControlVM
的 属性(/实例)。
注意:如果您还需要在 UserControlVM
中引用 MainWindowVM
,请将其传递给构造函数并将其存储为 属性。
在 xaml 中看起来像这样(在 MainWindow.xaml
中):
<ContentControl Content="{Binding UserControlVMInstance}"/>
别忘了 DataTemplate
:
<DataTemplate DataType="{x:Type vm:UserControlVM}">
<view:UserControlView/>
</DataTemplate>
问题更新后编辑:
这是一个示例,其中包含您的部分代码,用于演示 WPF 和 MVVM 的实际应用。您只需在 UserControl.Resources
中定义 DataTemplate
,然后通过 Binding
为 ContentControl
提供 UserControlVM
的一个实例。 WPF 知道此类型有一个 DataTemplate
,并将在 ContentControl
所在的位置添加一个 UserControlView
的实例。
<MainWindow>
<MainWindow.Resources>
<DataTemplate DataType="{x:Type vm:UserControlVM}">
<view:UserControlView/>
</DataTemplate>
</MainWindow.Resources>
<!-- Your TabControl -->
<TabControl>
<!--Result View-->
<TabItem Header="{Binding TabImportHeader}">
<ContentControl Content="{Binding TabImportCONTENT}"/>
</TabItem>
</TabControl>
</MainWindow>
Microsoft WPF 控件是使用 DependencyProperties 构建的
DependencyProperty 支持以下功能,在引入特定于控件的视图模型时您将失去这些功能:
DP可以在样式/触发器中设置(样式和模板很重要,开发人员经常希望重用控件的功能,但完全改变外观)
DP可以通过数据绑定设置(包括2个控件之间的交叉绑定)
DP可以从元素树中的父元素自动继承它的值
DP可以动画
在 ViewModel 之间共享资源是一种常见的情况,但是如果它确实成为问题,它通常是架构中出现问题或缺乏问题的一个很好的指标。
最简单的解决方案是让 UserControlVM
持有对 MainWidowVM
的引用并订阅某个事件,该事件由接口通过 Command
调用。然而,声明功能的 ViewModels
之间的交叉引用可能会变得非常混乱,交叉引用和循环引用最终会阻止 GarbageCollection
正确完成其工作,从而导致不必要的内存泄漏。
您还可以让您的 MainWindowVM
保留对每个其他 ViewModel
的引用,以通过至少集中交叉引用来提供集中的通信点。
下一个最简单的解决方案是使用 weak event binding 实现类似外部消息传递系统的东西。这摆脱了其他对象中对象的固定引用,但代价是性能极其沉重。如果您正在开发的应用程序具有例如包含 select 元素的主列表和不同 windows 中的许多模块化详细列表,这可能是可行的 - 来自 1 个主端的单向通信具有不频繁的更改和异步许多细节端的实现。对于您的目的,这应该没问题,如果这些事件将自动触发,但我建议完全采用不同的路由器。
上面列出的问题就是为什么MVVM不仅有Model
、ViewModel
和View
而且通常还用Services
来封装共享逻辑and/or 数据(资源)从 ViewModels
转移到有效的共享资源中。
您的 ViewModel(例如,在 LocalizationService
的情况下可能还有视图)将保存对服务的引用,并且通常都指向该服务的单个实例。这也消除了不需要的交叉引用,并允许正确绑定和正确(取消)订阅事件,而不会受到弱绑定的性能影响。
使用 Services
而不是交叉引用 ViewModels
的另一个好处是,它确实让您有机会实际遵循 SOLID principles of object-oriented programming 并在其所属的位置拥有逻辑,而无需重复。
之后可以使用 IoC-Container 在运行时正确地注入引用和依赖项,但是这会带来隐藏依赖项的风险以及项目设置、文档等方面的大量准备时间.如果第一次做的不对and/or。我个人不会走这条路,除非团队中的每个成员都真正知道他们在做什么。