【问题标题】:Binding UserControl Command to MainWindow WPF/MVVM将 UserControl 命令绑定到 MainWindow WPF/MVVM
【发布时间】:2018-02-02 13:39:49
【问题描述】:

我有一个 UserControl,它只是一个简单的 DataGrid 来显示一些东西,它有自己的 ViewModel 和 Model。

我希望每当我点击 DataGrid 时,都会引发一个事件。到目前为止,它正在使用命令,并且我在我的 UserControl.ViewModel 上获得了该事件。

问题是我需要在 MainWindow.ViewModel 中引发事件,它包含加载 UserControl.DataGrid 中所需内容的逻辑。

在我对 WPF 和 MVVM 的了解不多的情况下,我有以下几种选择:

  • UserControl.DataGridClicked 的 DependencyProperty(我想避免,并尽可能坚持使用 MVVM)
  • 将 MainWindow.ViewModel 实例提供给我的 UserControl.ViewModel 的构造函数,以便我可以直接引发事件。
  • 创建一个 BusinessLogic 类,并将逻辑放在那里,这样我就可以在 UserControl.ViewModel 或 MainWindow.ViewModel 上调用它。
  • ?

这就是我如何称呼我的 UserControl:

<Window>
    <Grid>
        <TabControl>
            <TabItem Header="{Binding Model.TabImportHeader}">
                <views:ResultView DataContext="{Binding ResultViewModel}"/>
            </TabItem>
        </TabControl>
    </Grid>
</Window>

这是我的用户控件:

<UserControl x:Class="ResultView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:viewModels="clr-namespace:ViewModels"
             mc:Ignorable="d"
             d:DataContext="{d:DesignInstance Type=viewModels:ResultViewModel, IsDesignTimeCreatable=False}">

    <!--DataGrid-->
    <DataGrid ItemsSource="{Binding Model.ObservableCollection}"
              ColumnWidth="*"
              AutoGenerateColumns="false"
              IsReadOnly="True"
              BorderThickness="0"
              Background="White"
              HeadersVisibility="Column">

        <!--InputBindings-->
        <DataGrid.InputBindings>
            <MouseBinding Gesture="LeftClick"
                          Command="{Binding LeftClickCommand}">

            </MouseBinding>
        </DataGrid.InputBindings>
        <!--InputBindings-->

        <DataGrid.Columns>
            <DataGridTextColumn Header="Filename"
                                Binding="{Binding FileInfo.Name}"
                                Width="Auto" />
        </DataGrid.Columns>
    </DataGrid>
</UserControl>

有知道一些好的做法的 WPF 大师吗?我将非常感谢任何帮助。

提前致谢。

编辑:命令声明:

public ICommand = new RelayCommand(LeftClick, () => true);

【问题讨论】:

  • 你又犯了同样的错误。您的 UserControl 不能有自己的视图模型。
  • 是的,你告诉我我不应该在 UserControl 中有 viewModel,因为我会覆盖 dataContext,但我解决了这个问题,这里的问题与你标记的重复问题完全不同。
  • &lt;views:ResultView/&gt; 在 ResultViewModel 的 DataTemplate 中要求控件继承 DataContext。如果显式设置,DataTemplate 就没用了。
  • 我离开 &lt;UserControl.DataContext&gt;&lt;viewModels:ResultViewModel /&gt;&lt;/UserControl.DataContext&gt; 主要是因为我收到设计错误,说由于未知的 DataContext 无法解决符号
  • 您应该有一个设计时数据上下文,如here 所述。说真的,你应该先解决这个问题,否则 DataTemplate 将无法正常工作。如果您实际上不需要 DataTemplate,请将其从问题中删除。

标签: c# wpf mvvm user-controls


【解决方案1】:

您可以使用{RelativeSource} 直接绑定到MainWindowViewModel 中的命令:

<MouseBinding Gesture="LeftClick" Command="{Binding DataContext.CommandPropertyInMainWindowVm, RelativeSource={RelativeSource AncestorType=Window}}" />

或者您可以绑定到UserControlViewModel 的命令,该命令使用事件聚合器或消息总线发布事件。然后MainWindowViewModel 将订阅此事件。请参阅以下博客文章了解更多信息:https://blog.magnusmontin.net/2014/02/28/using-the-event-aggregator-pattern-to-communicate-between-view-models/

使用事件聚合器在两个组件(例如两个视图模型)之间进行通信,消除了事件发布者和订阅者之间的紧密耦合。两个视图模型都有对事件聚合器的引用,但它们彼此之间没有任何关系。这是在 MVVM 中以松耦合方式在视图模型之间进行通信时的最佳实践。

您将需要一个事件聚合器实现。大多数 MVVM 库都包含一个。在Prism 中,该类称为EventAggregator。在Mvvm Light 中称为Messengerhttps://marcominerva.wordpress.com/2014/06/25/how-to-send-string-and-content-messages-with-mvvm-light-messenger/。不过概念是一样的。

【讨论】:

  • 感谢您的回答,直接绑定按预期工作,但我也会看看 EventAggregator。感谢您的链接!
猜你喜欢
  • 2011-04-04
  • 2014-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多