如何找到 ICommand 绑定目标(控件)

发布于 2024-12-09 21:56:34 字数 228 浏览 1 评论 0原文

我们使用MVVM模式。在视图中,我将保存命令绑定到按钮:

在视图模型中,我想找出保存命令绑定目标,可以吗?

    private Button GetBindingControl(ICommand command)
    {
        // What should I do here:

        return button;
    }

We use the MVVM pattern. In the View, I have binding the save command to a button:

In the view model, I would like to find out the save command binding target, does it possible?

    private Button GetBindingControl(ICommand command)
    {
        // What should I do here:

        return button;
    }

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

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

发布评论

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

评论(2

私野 2024-12-16 21:56:34

这是不可能的,而且它违背了 MVVM 的目的(无论使用什么控件,都在 VM 中保留 UI 逻辑)

也许您可以问您要解决的问题是什么。

It's not possible, and it defeats the purpose of MVVM (having the UI logic in the VM regardless of the controls used)

Maybe you could ask instead what problem you are trying to solve.

你的他你的她 2024-12-16 21:56:34

正如 @Diego 所说,这违背了 MVVM 的目的,因为我们必须努力不在 MVVM 的视图模型中包含视觉效果或控件...

话虽如此,有两个选项...

  1. 使用 RoutedCommands
  2. 使用附加行为。

RoutedCommands 在 MVVM 中不容易被允许,因为它们需要将命令紧密绑定到 UI 元素,即在我们的例子中为 Button。因此它们也违背了 MVVM 的目的。

但 MVVM 很高兴与附加行为共存。

许多开发人员回避这个极其强大的功能。我们可以将它与 RoutedCommands 一起使用。

在您的情况下

  1. ,使用操作委托附加到按钮。
  2. 将字符串对象附加为命令参数。
  3. 在行为内部,使用一些路由命令设置 Button.Command。
  4. 在执行的事件处理程序中,从发送者/originalsource/source 获取按钮操作委托作为按钮,然后调用您的 Action<>相应地,通过使用 e.Parameter 字符串值。

下面的示例代码...

假设您有签名 Action 的常见按钮实用程序

public static class ButtonActionUtilities
{
    public static Action<Button, string> ButtonActionDelegate
    {
        get
        {
            return ExecuteButtonClick;
        }
    }

    public static void ExecuteButtonClick(Button btn, string param)
    {
        MessageBox.Show(
          "You clicked button " + btn.Content + " with parameter " + param);
    }
}

,那么附加的行为如下...

public static class ButtonAttachedBehavior
{
    public static readonly DependencyProperty ActionDelegateProperty
        = DependencyProperty.RegisterAttached(
            "ActionDelegate",
            typeof(Action<Button, string>),
            typeof(ButtonAttachedBehavior),
            new PropertyMetadata(null, OnActionDelegatePropertyChanged));

    public static Action<Button, string> GetActionDelegate(
                                            DependencyObject depObj)
    {
        return (Action<Button, string>)depObj.GetValue(
                                            ActionDelegateProperty);
    }

    public static void SetActionDelegate(
         DependencyObject depObj, Action<Button, string> value)
    {
        depObj.SetValue(ActionDelegateProperty, value);
    }

    private static void OnActionDelegatePropertyChanged(
        DependencyObject depObj,
        DependencyPropertyChangedEventArgs e)
    {
        if (depObj is Button
            && e.NewValue is Action<Button, string>)
        {               
            ((Button)depObj).Command
                = new RoutedCommand(
                        "ActionRoutedCommand",
                         typeof(ButtonAttachedBehavior));
            ((Button) depObj).CommandBindings.Add(
                new CommandBinding(
                    ((Button) depObj).Command,
                    OnActionRoutedCommandExecuted));
        }
    }

    private static void OnActionRoutedCommandExecuted(
       object sender, ExecutedRoutedEventArgs e)
    {
        var actionDelegate = GetActionDelegate((Button)e.Source);
        actionDelegate((Button) e.Source, (string)e.Parameter);
    }
}

在 XAML 上它将如下所示

      <StackPanel>
         <Button x:Name="TestButton" Content="Test Me" 
            local:ButtonAttachedBehavior.ActionDelegate
                ="{x:Static local:ButtonActionUtilities.ButtonActionDelegate}"
            CommandParameter
                ="{Binding Text, ElementName=ParameterTextBox}"/>

          <TextBox x:Name="ParameterTextBox"/>
      </StackPanel>

...使用上面的代码,您只需将 ActionDelegate 附加属性设置为适当的委托,它就会执行该委托。

我仍然建议您修改现有的代码设置,以分离按钮特定的行为,使其对 MVVM 更加友好。

As @Diego said, this defats the purpose of MVVM because we must try hard not to include visuals or controls in the view models in MVVM...

Having said that there are two options...

  1. Using RoutedCommands
  2. Using Attached Behaviors.

RoutedCommands are not readily allowed in MVVM as they need to be closely command bound to the UI element i.e. in our case the Button. Hence they too defeat the purpose of MVVM.

But MVVM happily co-exists with the Attached Behaviors.

Many developers shy away from this immensely powerful feature. And we can use it along with RoutedCommands.

In your case

  1. Attach to the Button, with a Action delegate.
  2. Attach the string object as command parameter.
  3. Inside the behavior, set the Button.Command with some Routed command.
  4. In the executed event handler, get the button action delegate from the sender / originalsource / source as the button and then call your Action<> accordingly by using e.Parameter string value.

Sample code below...

Assume you have common button utilities of signature Action<Button, string>

public static class ButtonActionUtilities
{
    public static Action<Button, string> ButtonActionDelegate
    {
        get
        {
            return ExecuteButtonClick;
        }
    }

    public static void ExecuteButtonClick(Button btn, string param)
    {
        MessageBox.Show(
          "You clicked button " + btn.Content + " with parameter " + param);
    }
}

Then the attched behavior is as below...

public static class ButtonAttachedBehavior
{
    public static readonly DependencyProperty ActionDelegateProperty
        = DependencyProperty.RegisterAttached(
            "ActionDelegate",
            typeof(Action<Button, string>),
            typeof(ButtonAttachedBehavior),
            new PropertyMetadata(null, OnActionDelegatePropertyChanged));

    public static Action<Button, string> GetActionDelegate(
                                            DependencyObject depObj)
    {
        return (Action<Button, string>)depObj.GetValue(
                                            ActionDelegateProperty);
    }

    public static void SetActionDelegate(
         DependencyObject depObj, Action<Button, string> value)
    {
        depObj.SetValue(ActionDelegateProperty, value);
    }

    private static void OnActionDelegatePropertyChanged(
        DependencyObject depObj,
        DependencyPropertyChangedEventArgs e)
    {
        if (depObj is Button
            && e.NewValue is Action<Button, string>)
        {               
            ((Button)depObj).Command
                = new RoutedCommand(
                        "ActionRoutedCommand",
                         typeof(ButtonAttachedBehavior));
            ((Button) depObj).CommandBindings.Add(
                new CommandBinding(
                    ((Button) depObj).Command,
                    OnActionRoutedCommandExecuted));
        }
    }

    private static void OnActionRoutedCommandExecuted(
       object sender, ExecutedRoutedEventArgs e)
    {
        var actionDelegate = GetActionDelegate((Button)e.Source);
        actionDelegate((Button) e.Source, (string)e.Parameter);
    }
}

And on XAML it will look like this....

      <StackPanel>
         <Button x:Name="TestButton" Content="Test Me" 
            local:ButtonAttachedBehavior.ActionDelegate
                ="{x:Static local:ButtonActionUtilities.ButtonActionDelegate}"
            CommandParameter
                ="{Binding Text, ElementName=ParameterTextBox}"/>

          <TextBox x:Name="ParameterTextBox"/>
      </StackPanel>

So with the code above you will need to just set the ActionDelegate attached property to approapriate delegate and it will execute that.

I would still suggest you to revamp your existing code setup to separate button specific behaviors to make it more MVVM friendly.

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