【问题标题】:Binding an event to a control created with a data template in WPF将事件绑定到使用 WPF 中的数据模板创建的控件
【发布时间】:2017-06-26 13:17:15
【问题描述】:

在我的 WPF 项目中,我在 Code Behind 中创建了一个自定义 ListView。在此 ListView 中有一个包含按钮的列,由我的资源字典中的数据模板定义。

<DataTemplate x:Key="DataTemplate_EditButton">
  <Button Style="{DynamicResource Button_Image}" Width="25" ... />
</DataTemplate>

当我初始化 ListView 时,我使用以下代码创建列:

GridViewColumn buttonColumn = new GridViewColumn();
DataTemplate dt = Application.Current.TryFindResource("DataTemplate_EditButton") as DataTemplate;
buttonColumn.CellTemplate = dt;
...

gridView.Columns.Add(buttonColumn);

现在我想将事件处理程序绑定到按钮的单击事件。我无法在模板中执行此操作,因为我需要为 Dictionary 类创建一个代码,并且无论如何我都需要 ListView-UserControl 中的事件处理程序。当我使用数据模板创建列时,当然无法访问为每一行创建的按钮。

处理以所述方式创建的按钮的点击事件的最佳方法是什么?

提前致谢,
弗兰克

【问题讨论】:

标签: c# wpf event-handling datatemplate


【解决方案1】:

由于您的模板在许多控件之间共享 - 好方法可能是使用路由命令。首先声明一个命令(或使用现有命令之一,例如来自ApplicationCommands 类):

public static class Commands {
    public static RoutedCommand EditRow = new RoutedCommand("Edit", typeof(Commands));
}

在您的模板中使用此命令:

<DataTemplate x:Key="DataTemplate_EditButton">
    <Button x:Name="button" Command="{x:Static my:Commands.EditRow}" />
</DataTemplate>

然后绑定到您的控件中的该命令(在构造函数中):

this.CommandBindings.Add(new CommandBinding(Commands.EditRow, EditButtonClicked));

private void EditButtonClicked(object sender, ExecutedRoutedEventArgs args) 
{
    var button = args.OriginalSource;
    // do what you need here
}

【讨论】:

  • 我已经对命令感到不满,但示例不如您的清晰。感谢您的解释! :)
  • 请注意,这些是路由命令。命令的其他(更常见)使用只是绑定到视图模型(&lt;Button Command={Binding EditCommand} /&gt;),但在您的情况下它似乎不适用(只是为了让您知道 wpf 中有不同类型的命令)。
  • 谢谢。如此少的代码,让我们的自定义控件保持整洁。很好的用法示例。
【解决方案2】:

处理以所述方式创建的按钮的点击事件的最佳方法是什么?

您需要等到Button 元素实际创建后才能附加事件处理程序。您可以通过为ListViewItemContainerGenerator 处理StatusChanged 事件来做到这一点。

请参考以下示例代码。它应该会给你这个想法。

private void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
{
    ItemContainerGenerator icg = sender as ItemContainerGenerator;
    if (icg.Status == System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated)
    {
        foreach (var item in icg.Items)
        {
            var container = icg.ContainerFromItem(item) as ListViewItem;
            Button button = FindVisualChild<Button>(container);
            if (button != null)
            {
                button.Click -= Button_Click;
                button.Click += Button_Click;
            }
        }
    }
}

private void Button_Click(object sender, RoutedEventArgs e)
{
    MessageBox.Show("clicked");
}

private static T FindVisualChild<T>(DependencyObject parent) where T : DependencyObject
{
    for (int childCount = 0; childCount < VisualTreeHelper.GetChildrenCount(parent); childCount++)
    {
        DependencyObject child = VisualTreeHelper.GetChild(parent, childCount);
        if (child != null && child is T)
            return (T)child;
        else
        {
            T childOfChild = FindVisualChild<T>(child);
            if (childOfChild != null)
                return childOfChild;
        }
    }
    return null;
}

【讨论】:

  • 我一直在寻找创建按钮后最好的事件。非常感谢您指出正确的。现在我需要找到一种方法将两个答案都标记为正确答案:D
猜你喜欢
  • 1970-01-01
  • 2012-08-18
  • 1970-01-01
  • 1970-01-01
  • 2011-05-10
  • 1970-01-01
  • 2011-10-29
  • 2011-04-01
  • 1970-01-01
相关资源
最近更新 更多