【问题标题】:How to handle WPF event in MVVM for nested controls in a Window如何在 MVVM 中为窗口中的嵌套控件处理 WPF 事件
【发布时间】:2012-01-04 19:23:16
【问题描述】:

最后说明 Final solution found in another post

虽然我很欣赏所提供的说明,但最终的解决方案实际上是由上面链接的另一个解决方案提供的。无论我尝试了什么,通过“元素名称”组件的绑定都不起作用。我必须根据数据网格上的“相对”层次结构...

<Button Name="btnPrintReport" 
   Command="{Binding DataContext.MyPrintCommand, 
             RelativeSource={RelativeSource FindAncestor, 
                             AncestorType={x:Type DataGrid}}}"
   CommandParameter="{Binding}"
   Height="16" Width="16" HorizontalAlignment="Center" >
   <Image Source="MyButtonImage.png" IsHitTestVisible="True"/>
</Button>

希望 WPF / MVVM 环境中的东西不要太复杂。这是场景。

我有一个窗口 (.xaml) 和一个相应的视图模型 (.cs)。表单显示良好,所有数据绑定都没有问题。 (注意:这不是通过任何商业“框架”完成的)

视图窗口中的控件之一是数据网格的自定义用户控件,其中包含所有预定义的列、标题和在显示视图时显示的内容。即使控件没有直接在主窗口 .xaml 文件中“定义”,但只是作为用户控件本身(它有自己明显的 .cs 代码隐藏)放在表单上,​​这也没有问题。

主窗口的“DataContext”指向视图模型,以及具有数据网格的用户控件

<DataGrid AutoGenerateColumns="False" 
    Name="dataMyStuff"
    ItemsSource="{Binding Path=MyTablePropertyOnViewModel, 
        NotifyOnSourceUpdated=True, 
        NotifyOnTargetUpdated=True}" ... />

现在,我正在寻找什么。在这个数据网格上,我有一列在第一列中有一个图像。当我单击此图像时,我想打印此行表示的特定于记录的报告(它具有我使用的 PK 值)。那么,我如何告诉图像“KeyUp”事件转到 View Model 事件处理程序,因为那是数据所在的位置,以及我需要一些其他方法来准备对报告的调用。网格的视图部分用于向用户显示外观,因此该控件中没有直接的“功能”。

-- EDIT -- 每个答案的进度

我已经从 Josh 和 Rachel 调整了每个 cmets 的数据网格,但是,有些事情似乎仍然不太正确...看到按钮使用“命令”实例,我将其解释为它需要附加到我的视图模型上的“ICommand”接口对象的实例。所以,我创建了一个实例。我知道命令处理程序可以工作,因为它也用于添加、编辑、保存、取消、退出等常见的事情......所以我有一个新的用于打印目的。为简单起见,我将它创建为始终执行,因此没有方法可以处理控件的“CanExecute”部分。我已经将按钮的“命令”设置为几乎所有我能想到的迭代,但这里是我所看到的更新。

<UserControl>
   <Data grid columns / template, etc to the button>
      <DataTemplate> 
         <Button Name="btnPrintReport" 
            Command="{Binding DataContext.MyPrintCommand}" >
            <Image Source="myPrintImage.png"/>
         </Button>
      </DataTemplate>
   </Data grid columns, etc>
</UserControl>

在我的 ViewModel 类中(myICommandButtonHandler 继承自 ICommand)

private myICommandButtonHandler myPrintCommand;
public myICommandButtonHandler MyPrintCommand
{
   get { if (myPrintCommand == null)
            myPrintCommand = new myICommandButtonHandler(myPrint);
         return myPrintCommand;
       }
}

private void myPrint()
{
   MessageBox.Show( "Doing the print job..." );
}

现在,我所看到的。在逐步初始化所有控件等期间。我单击菜单项以调用要显示的窗口。首先,它创建一个 View Model 控制器的实例。然后,它调用 Window 并将 View Model 控制器作为参数传递,因此它立即在 Window 级别设置为窗口的“DataContext”。然后主窗口进入它的“InitializeComponents”调用并开始构建所有其他嵌入的控件,包括这个包含相关数据网格的单独类。在此用户控件(具有数据网格)的构造函数中,尚未设置“数据上下文”,因为其余控件尚未初始化,我不知道为什么/何时“绑定”显然得到“挂钩”。因此,尝试绑定到数据网格的命令按钮似乎失败了。但是,在运行时,实际数据会在网格中更新,所以我知道有很多工作。

因此,数据网格将其“ItemsSource”设置为视图模型上“DataView”属性的属性,但“按钮”的绑定似乎没有看到我认为的“MyPrintCommand”处理程序会受到打击.. 它的作用是只显示一个消息框(现在)。

【问题讨论】:

  • 有几件事: 1. 显示如何将数据上下文绑定到 UserContorl 的代码。 2. Button 上的绑定看起来“关闭”Binding DataContext.MyPrintCommand。它可能应该是Binding MyPrintCommandBinding ElementName=SomeControl, DataContext.MyPrintCommand

标签: c# wpf event-handling nested-controls


【解决方案1】:

通常我使用AttachedCommand Behavior,它允许我将事件绑定到 ViewModel 命令。例如,您可以使用

<Image ...
       local:CommandBehavior.Event="KeyUp"  
       local:CommandBehavior.Command="{Binding DataContext.PrintCommand, ElementName=dataMyStuff}"
       local:CommandBehavior.CommandParameter="{Binding }"/>

我建议使用与 KeyUp 不同的事件,因为我认为图像不能具有键盘焦点,因此不会触发 KeyUp 事件。

更好的选择是使用按钮并将其模板覆盖为您的图像。这将维护Click 功能,并让您可以访问CommandCommandParameter 属性

<Button Command="{Binding DataContext.PrintCommand, ElementName=dataMyStuff}"
        CommandParameter="{Binding }">
    <Button.Template>
        <Image ... />
    </Button.Template>
</Button>

另外,CommandParameter="{Binding }" 将简单地将当前 DataRow 的 DataContext(您的数据对象)传递给命令

【讨论】:

  • 我已经根据您的回答内容更新了我的问题,但仍然卡住了......我提供的额外帮助是否进一步?
  • @DRapp 注意命令绑定中的ElementName。每行的默认DataContext 将是行的数据对象,它可能没有PrintCommand。我在绑定中使用ElementName 来告诉绑定查找DataGrid 以转到名为dataMyStuff 的DataGrid 并绑定到DataGrid.DataContext.PrintCommand。如果同一个对象同时包含 PrintCommandMyTablePropertyOnViewModel,这将起作用
  • 但是我的数据网格没有打印命令(ICommand)处理程序。 VIEW MODEL 确实...我想这就是我所缺少的,但是,我也会查看 Element Name 组件。
  • @DRapp 这就是为什么我绑定到DataContext.PrintCommand,而不是PrintCommand。这使得绑定点指向DataGrid.DataContext.PrintCommand,其中DataContext 是您的ViewModel。
【解决方案2】:

将数据模板更改为以图像为内容的按钮。使用按钮上的 command 和 commandparameter 属性来调用您的打印方法。您可以在视图模型中声明您的打印命令,并绑定到它。您的参数可以是数据网格中的选定行。

【讨论】:

  • 听起来很有希望,但我试图避免使用带有边框和所有内容的实际“按钮”外观,但会试一试。
  • 将按钮模板化为仅图像。它的行为就像一个按钮,但它只显示图像,就好像它没有嵌套在按钮内一样。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-05-27
  • 2013-01-30
  • 1970-01-01
  • 1970-01-01
  • 2015-04-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多