MVVM-Light,从数据网格列模板内的按钮触发事件

发布于 2024-09-10 13:32:46 字数 2039 浏览 2 评论 0原文

学习 MVVM light 是一种乐趣,但我被困住了。问题是事件触发。

在下面的代码中,一键工作并触发事件。另一个按钮没有。输出中未报告任何绑定错误。我有什么明显遗漏的吗?

<Grid x:Name="LayoutRoot">...
<StackPanel>
  <Button Content="THIS BUTTON WORKS">
    <i:Interaction.Triggers>
      <i:EventTrigger EventName="Click">
        <Command:EventToCommand Command="{Binding DataContext.HandleAddQuestionActionCommand, ElementName=LayoutRoot, Mode=OneWay}" PassEventArgsToCommand="True"/>
      </i:EventTrigger>
    </i:Interaction.Triggers>
  </Button>
  <sdk1:DataGrid ItemsSource="{Binding QuestionActions}" AutoGenerateColumns="False" >
    <sdk1:DataGrid.Columns>
      <sdk1:DataGridTextColumn Binding="{Binding Answer.Name}" Header="Answer"/>
        <sdk1:DataGridTemplateColumn Header="Edit">
          <sdk1:DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
              <Button Content="THIS BUTTON DONT WORK" >
                <i:Interaction.Triggers>
                  <i:EventTrigger EventName="Click">
                    <Command:EventToCommand Command="{Binding DataContext.HandleEditQuestionActionCommand, ElementName=LayoutRoot, Mode=OneWay}" PassEventArgsToCommand="True"/>
                  </i:EventTrigger>
                </i:Interaction.Triggers>
              </Button>
            </DataTemplate>
          </sdk1:DataGridTemplateColumn.CellTemplate>
        </sdk1:DataGridTemplateColumn>
    </sdk1:DataGrid.Columns>
  </sdk1:DataGrid>
</StackPanel>

视图模型代码:

public RelayCommand<RoutedEventArgs> HandleAddQuestionActionCommand {
    get; private set;
}
public RelayCommand<RoutedEventArgs> HandleEditQuestionActionCommand {
    get; private set;
}


HandleAddQuestionActionCommand = new RelayCommand<RoutedEventArgs>(e =>{...});
HandleEditQuestionActionCommand = new RelayCommand<RoutedEventArgs>(e =>{...});

MVVM light has been a pleasure to learn, but here I am stuck. The problem is event firing.

In the code below, one button the works and fires events. The other button doesnt. No binding errors are reported in the output. Is there anything obvious I am missing?

<Grid x:Name="LayoutRoot">...
<StackPanel>
  <Button Content="THIS BUTTON WORKS">
    <i:Interaction.Triggers>
      <i:EventTrigger EventName="Click">
        <Command:EventToCommand Command="{Binding DataContext.HandleAddQuestionActionCommand, ElementName=LayoutRoot, Mode=OneWay}" PassEventArgsToCommand="True"/>
      </i:EventTrigger>
    </i:Interaction.Triggers>
  </Button>
  <sdk1:DataGrid ItemsSource="{Binding QuestionActions}" AutoGenerateColumns="False" >
    <sdk1:DataGrid.Columns>
      <sdk1:DataGridTextColumn Binding="{Binding Answer.Name}" Header="Answer"/>
        <sdk1:DataGridTemplateColumn Header="Edit">
          <sdk1:DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
              <Button Content="THIS BUTTON DONT WORK" >
                <i:Interaction.Triggers>
                  <i:EventTrigger EventName="Click">
                    <Command:EventToCommand Command="{Binding DataContext.HandleEditQuestionActionCommand, ElementName=LayoutRoot, Mode=OneWay}" PassEventArgsToCommand="True"/>
                  </i:EventTrigger>
                </i:Interaction.Triggers>
              </Button>
            </DataTemplate>
          </sdk1:DataGridTemplateColumn.CellTemplate>
        </sdk1:DataGridTemplateColumn>
    </sdk1:DataGrid.Columns>
  </sdk1:DataGrid>
</StackPanel>

ViewModel code:

public RelayCommand<RoutedEventArgs> HandleAddQuestionActionCommand {
    get; private set;
}
public RelayCommand<RoutedEventArgs> HandleEditQuestionActionCommand {
    get; private set;
}


HandleAddQuestionActionCommand = new RelayCommand<RoutedEventArgs>(e =>{...});
HandleEditQuestionActionCommand = new RelayCommand<RoutedEventArgs>(e =>{...});

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

乖不如嘢 2024-09-17 13:32:46

由于 DataGrid.Columns 不是依赖项属性,因此您的数据上下文在 DataGrid DataGridTemplateColumn 中丢失。因此,您无法在 DataGridTemplateColumn 中使用元素到元素的数据绑定。

不过,借助 MVVM Light Toolkit 的 ViewModelLocator,这个问题很容易解决。

我不知道你的 ViewModel 叫什么,但假设它是 MainViewModel 你可以将按钮绑定更改为:

<sdk1:DataGridTemplateColumn Header="Edit">
    <sdk1:DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <Button Content="THIS BUTTON WILL WORK NOW ;-)" >
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="Click">
                        <Command:EventToCommand Command="{Binding Source={StaticResource Locator},
                                                                  Path=MainViewModel.HandleEditQuestionActionCommand}"
                                                PassEventArgsToCommand="True" />
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </Button>
        </DataTemplate>
    </sdk1:DataGridTemplateColumn.CellTemplate>
</sdk1:DataGridTemplateColumn>

Your data context is lost in the DataGrid DataGridTemplateColumn since the DataGrid.Columns isn't a dependency property. Because of this, you can't use element-to-element data binding from within your DataGridTemplateColumn.

However, this is easily fixed thanks to MVVM Light Toolkit's ViewModelLocator.

I don't know what your ViewModel is called, but assuming it is MainViewModel you can change your button binding to this:

<sdk1:DataGridTemplateColumn Header="Edit">
    <sdk1:DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <Button Content="THIS BUTTON WILL WORK NOW ;-)" >
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="Click">
                        <Command:EventToCommand Command="{Binding Source={StaticResource Locator},
                                                                  Path=MainViewModel.HandleEditQuestionActionCommand}"
                                                PassEventArgsToCommand="True" />
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </Button>
        </DataTemplate>
    </sdk1:DataGridTemplateColumn.CellTemplate>
</sdk1:DataGridTemplateColumn>
太傻旳人生 2024-09-17 13:32:46

DataGrid 内的按钮具有 QuestActions 的 DataContext,因为绑定基于 DataGrid 的 ItemSource 属性。在这种情况下,您需要找到 DataGrid 本身的 DataContext(或 UserControl 或在其 DataContext 中具有 Command 的任何父级)才能访问您的 Command:

<Command:EventToCommand 
Command="{Binding RelativeSource={RelativeSource FindAncestor, 
AncestorType={x:Type sdk1:DataGrid}}, 
Path=DataContext.ViewSchemaCommand, Mode=OneWay}" 
PassEventArgsToCommand="True" />

The button inside the DataGrid has a DataContext of QuestActions since the Binding is based on the the DataGrid's ItemSource Property. That being the case, you'll need to find the DataContext of the DataGrid itself (or the UserControl or whatever parent that has the Command in it's DataContext) to get to your Command:

<Command:EventToCommand 
Command="{Binding RelativeSource={RelativeSource FindAncestor, 
AncestorType={x:Type sdk1:DataGrid}}, 
Path=DataContext.ViewSchemaCommand, Mode=OneWay}" 
PassEventArgsToCommand="True" />
近箐 2024-09-17 13:32:46

该解决方案仅适用于静态视图模型。查看 Dan Whalin 的页面以获取替代答案。

您可以像这样创建资源(不要忘记您的参考):

<UserControl.Resources>
     <controls:DataContextProxy x:Key="DataContextProxy" />
</UserControl.Resources>

<sdk:Page.Resources>
    <controls:DataContextProxy x:Key="DataContextProxy"/>
</sdk:Page.Resources>

像这样在控件中使用:

<sdk:DataGridTemplateColumn>
<sdk:DataGridTemplateColumn.CellTemplate>
    <DataTemplate>
        <Button Content="Content">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <cmd:EventToCommand Command="{Binding Source={StaticResource DataContextProxy}, Path=DataSource.MyCommand}"
                                        CommandParameter="{Binding Path=SomeValue}"
                                        PassEventArgsToCommand="False">     
                    </cmd:EventToCommand>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>
    </DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>

视图模型
定义RelayCommand:

public RelayCommand<object> MyCommand { get; set; }

在构造函数中设置RelayCommand:

MyCommand = new RelayCommand<object>((e) =>
        {
            if (e != null && e is int)
            {
                int varName = int.Parse(e.ToString());

                //DoSomething...
            }
        });

This solution only works for static view models. check out Dan Whalin's page out for an alternative answer. http://weblogs.asp.net/dwahlin/archive/2009/08/20/creating-a-silverlight-datacontext-proxy-to-simplify-data-binding-in-nested-controls.aspx

You can create a resource like so (don't forget your reference):

<UserControl.Resources>
     <controls:DataContextProxy x:Key="DataContextProxy" />
</UserControl.Resources>

or

<sdk:Page.Resources>
    <controls:DataContextProxy x:Key="DataContextProxy"/>
</sdk:Page.Resources>

Use in control like so:

<sdk:DataGridTemplateColumn>
<sdk:DataGridTemplateColumn.CellTemplate>
    <DataTemplate>
        <Button Content="Content">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <cmd:EventToCommand Command="{Binding Source={StaticResource DataContextProxy}, Path=DataSource.MyCommand}"
                                        CommandParameter="{Binding Path=SomeValue}"
                                        PassEventArgsToCommand="False">     
                    </cmd:EventToCommand>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </Button>
    </DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>

ViewModel
Define RelayCommand:

public RelayCommand<object> MyCommand { get; set; }

Set RelayCommand in Constructor:

MyCommand = new RelayCommand<object>((e) =>
        {
            if (e != null && e is int)
            {
                int varName = int.Parse(e.ToString());

                //DoSomething...
            }
        });
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文