【问题标题】:How to databind Click= to a function on the object and not the page如何将 Click= 数据绑定到对象而不是页面上的函数
【发布时间】:2025-12-14 12:00:02
【问题描述】:

我正在使用 Silverlight,但我也对 WPF 答案感兴趣

我有一个数据绑定到“收藏夹”链接列表的列表。每个收藏夹都包含一个姓名和一个电话号码。

列表绑定到描述图形方面的 DataTemplate。在这个模板中有一个按钮——拨号。当您单击该按钮时,我希望调用收藏夹的 Dial() 方法。现在调用页面/窗口的 Dial 方法。

如果这是不可能的,有没有办法让收藏夹以某种方式附加到按钮上?这样我就知道哪个收藏夹与按钮按下相关联?

下面的 XAML 不起作用,Text="{Binding Name}" 很好用,因为它绑定到收藏夹上的 Name 属性,但 Click="{Binding Dial}" 不会调用收藏夹上的 Dial()。

    <DataTemplate x:Key="DataTemplate1">
        <StackPanel d:DesignWidth="633" Orientation="Horizontal" Height="93">
            <Button x:Name="DialButton" Content="Edit" Click="{Binding Dial}"/>
            <TextBlock x:Name="TextBlock" TextWrapping="Wrap" Text="{Binding Name}" FontSize="64" Height="Auto" FontFamily="Segoe WP SemiLight"/>                                      
        </StackPanel>
    </DataTemplate>

【问题讨论】:

    标签: wpf silverlight data-binding


    【解决方案1】:

    所以它应该去:

    <Button CommandParameter="{Binding}" Command="{Binding Dial}"/>
    

    然后您将收到数据对象作为命令参数。在这种情况下,您必须提供一个名为 Dial 的属性并返回一个 ICommand 实现。如果该属性在您的数据对象上但在主类(代码隐藏)上不可用,则必须在绑定中查找它,为此使用 RelativeSource 关键字。


    另一种方法是制作点击处理程序。在单击处理程序中,您可以将发送者转换为 Button(或 FrameworkElement),然后从 DataContext 获取数据对象。我假设您尝试创建这样的解决方案。

    private void Button_Click(object sender, RoutedEventArgs e) {
        Button btn = (Button)sender;
        MyObject obj = btn.DataContext as MyObject; 
        if(null != obj){
             obj.Dial();
             // or Dial(obj);
        }
    }
    

    标记必须如下:

    <Button x:Name="DialButton" Content="Edit" Click="Button_Click"/> 
    

    主要区别在于,我从 Click-Event 中删除了绑定并注册了一个事件处理程序。


    第三种解决方案是在Button.ClickEvent 后面的代码中注册一个处理程序。原理同第二个例子。

    我不太了解silverlight。或许还有一些其他的东西。

    【讨论】:

      【解决方案2】:

      HappyClicker 的第一个解决方案是大多数用途的最佳解决方案,因为它支持良好的设计模式,例如 MVVM。

      还有另一种简单的方法可以使用附加属性获得相同的结果,因此您可以编写:

      <Button Content="Edit" my:RouteToContext.Click="Edit" />
      

      并且 Edit() 方法将在按钮的 DataContext 上被调用。

      以下是 RouteToContext 类的实现方式:

        public class RouteToContext : DependencyObject
        {
          public static string GetClick(FrameworkElement element) { return (string)element.GetValue(ClickProperty); }
          public static void SetClick(FrameworkElement element, string value) { element.SetValue(ClickProperty, value); }
          public static DependencyProperty ClickProperty = ConstructEventProperty("Click");
      
          // Additional proprties can be defined here
      
          private static DependencyProperty ConstructEventProperty(string propertyName)
          {
            return DependencyProperty.RegisterAttached(
              propertyName, typeof(string), typeof(RouteToContext),
              new PropertyMetadata
              {
                PropertyChangedCallback = (obj, propertyChangeArgs) =>
                  obj.GetType().GetEvent(propertyName)
                    .AddEventHandler(obj, new RoutedEventHandler((sender, eventArgs) =>
                      ((FrameworkElement)sender).DataContext
                        .GetType().GetMethod((string)propertyChangeArgs.NewValue)
                        .Invoke(((FrameworkElement)sender).DataContext,
                          new object[] { sender, eventArgs }
                        )
                    ))
              }
            );
          }
        }
      

      工作原理:当RouteToContext.Click附加属性设置时,Type.GetEvent()用于查找名为“Click”的事件,并为其添加一个事件处理程序。此事件处理程序使用Type.GetMethod() 查找 DataContext 上的指定方法,然后调用 DataContext 上的方法,传递它收到的相同发送者和 eventArgs。

      【讨论】: