从MainWindow(WPF / MVVM)访问UserControl中的属性

时间:2018-01-24 12:59:01

标签: c# wpf mvvm user-controls

我有一点问题,我正在寻找实施它的正确方法。

我有一个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

3 个答案:

答案 0 :(得分:2)

MainWindowVMInstance.UserControlVMInstance.Property

UserControl位于MainWindow内。

因此,您的MainWindow具有UserControlVM的属性(/实例)。

注意:如果您还需要在MainWindowVM中引用UserControlVM,请将其传递给构造函数并将其存储为属性。

在xaml中它看起来像这样(在MainWindow.xaml内):

<ContentControl Content="{Binding UserControlVMInstance}"/>

别忘了DataTemplate

<DataTemplate DataType="{x:Type vm:UserControlVM}">
    <view:UserControlView/>
</DataTemplate>

问题更新后编辑:

这是一个示例,其中包含部分代码,用于演示WPF和MVVM的运行情况。您只需在DataTemplate中定义UserControl.Resources,然后通过ContentControl通过Binding提供UserControlVM的实例。 WPF知道此类型有DataTemplate,并会在UserControlView所在的地方添加ContentControl的实例。

<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>

答案 1 :(得分:2)

在ViewModels之间共享资源是一种常见的情况,但它通常是架构中出现问题的一个很好的指标 - 或者说缺乏 - 如果它确实成为一个问题。

最简单的解决方案是让UserControlVM保持对MainWidowVM的引用,并订阅某个事件,该事件由接口通过Command调用。然而,声明功能的ViewModels之间的交叉引用可能会变得非常混乱,因为交叉和循环引用最终会阻止GarbageCollection正确地执行其工作,从而导致不必要的内存泄漏。

您还可以让MainWindowVM保持对所有其他ViewModel的引用,通过至少集中进行交叉引用来提供集中的通信点。

下一个最简单的解决方案是使用weak event binding实现外部消息系统。这摆脱了其他对象中对象的固定引用,但代价是性能极其沉重。如果您正在开发一个应用程序,例如具有要选择的元素的主列表以及不同窗口中的许多模块化详细信息列表,这可能是可行的 - 从1个主端到单个通信的不频繁更改和许多细节端的异步实现。为了您的目的,这应该没问题,如果这些事件将自动触发,但我建议完全采用不同的路由器。

上面列出的问题是MVVM不仅具有Model s,ViewModelView的原因,而且通常还使用Services来封装共享逻辑和/或数据(资源)从ViewModels关闭到有效的共享资源。 您的ViewModel(例如,在LocalizationService的情况下可能是视图)将保留对服务的引用,并且通常都是对该服务的单个实例的引用。这也消除了不需要的交叉引用,并允许从事件中正确绑定和正确(非)订阅,而不会受到弱绑定的性能损失。

使用Services而不是交叉引用ViewModels的另一个好处是,它确实为您提供了实际关注SOLID principles of object-oriented programming并在其所属的地方拥有逻辑而无需重复的机会。

之后可以使用IoC-Container在运行时正确地注入引用和依赖项,但这会带来隐藏依赖项的风险,以及项目设置,文档等的大量准备时间。做得不合适和/或第一次。除非团队中的每个成员都知道他们在做什么,否则我个人不会走这条路。

答案 2 :(得分:1)

使用DependencyProperties构建Microsoft WPF控件

DependencyProperty支持以下功能,在引入特定于控件的视图模型时,您将失去这些功能:

  • DP可以在样式/触发器中设置(样式和模板很重要,开发人员通常希望重用控件的功能,但完全改变外观)

  • DP可以通过数据绑定设置(包括2个控件之间的交叉绑定)

  • DP可以从元素树中的父元素

  • 自动继承其值
  • DP可以设置动画