将一个方法绑定到XAML控件

3

我需要将一个方法绑定到XAML文件中的自定义控件,而不是该方法的结果。

基本上,当满足某些条件时,自定义控件将触发该方法多次。

我该怎么做呢?

我在互联网上找到了一些解决方案,但大多数都是将方法的结果绑定到XAML中,这并不是我要找的解决办法。

非常感谢。


感谢 ColinE 和 ChrisBD 的快速响应!但我认为命令不太适合我的情况,因为我们仍然需要基于自定义控件中的某些事件触发命令。不过我找到了一个解决方案,我将在下面分享它。 - tzuhsun
是的,我从这里得到了答案:https://dev59.com/62435IYBdhLWcg3w50f4#5156627。问题本身已经是我的答案了。 :) - tzuhsun
4个回答

2
有两种不同的方法可供使用:
  • 命令,公开一个类型为 ICommand 的属性,将其绑定到 UI 元素的 Command 属性上。
  • 使用行为将 UI 事件连接到视图模型中的方法,例如使用 MVVM LightEventToCommandBehavior

2

1

你能具体说明一下条件是什么吗?@ColineE和@ChrisBD正确指出,ICommands和EventTocommandBehavior在许多情况下都会有所帮助,例如将按钮单击或鼠标悬停事件转换为ViewModel中的方法调用。如果可以使用这些方法,我会建议使用它们,因为它们被认为是最佳实践

然而,有些情况需要比这更复杂的解决方案。一种解决方案是使用代码后台将DataContext强制转换为ViewModel类型并直接调用方法。例如:

// Inside MyViewModel.cs 
public class MyViewModel : INotifyPropertyChanged 
{ 
    // ... 
} 

// ...  
// Inside MyControl.xaml.cs 
public class MyControl : UserControl 
{ 
    public MyControl()  
    { 
        InitializeComponent();  
    } 

    pubilc void OnSomeConditionMatches() 
    { 
         var myViewModel = DataContext as MyViewModel; 
         if (myViewModel != null)  
         { 
              // Hacky, but it works
              myViewModel.CallCustomMethod();  
         }
    } 
}

这被认为是一种有点hacky的方法,并且在运行时会污染代码后台,使其了解ViewModel类型。这是我们想要避免的,因为它破坏了视图和ViewModel之间的关注点分离。

另一种方法是我自己使用的方法,当处理具有很少或没有数据绑定支持的自定义控件时。通过在视图上使用接口和附加属性,您可以将视图实例注入到ViewModel中并直接操作它。这是一种混合MVVM / MVP模式,我称之为MiVVM。

UML

MiVVM UML Diagram

Xaml:

<!-- Assumes myViewModel is the viewmodel we are binding to --> 
<!-- which has property InjectedUserControl of type IMyControl --> 
<Example3:MyControl DataContext="{StaticResource myViewModel}" 
                    Injector.InjectThisInto="InjectedUserControl"> 
</Example3:MyControl>

代码:

// Defines an interface to the usercontrol to  
// manipulate directly from ViewModel 
public interface IMyControl 
{ 
    // Our test method to call  
    void CallView(string message); 
} 

// Defines the usercontrol  
public partial class MyControl : UserControl, IMyControl 
{ 
    public MyControl() 
    { 
        InitializeComponent(); 
    } 

    public void CallView(string message) 
    { 
        MessageBox.Show(message); 
    } 
}

public class MyViewModel 
{ 
    private IMyControl myControl; 

    public IMyControl InjectedUserControl 
    { 
        set
        { 
            Debug.WriteLine(string.Format("Received Injected Control \"{0}\"", 
                value == null ? "NULL" : value.GetType().Name)); 

            this.myControl = value; 
            this.OnInjectedObjectsChanged(); 
        } 
    } 

    private void OnInjectedObjectsChanged() 
    { 
        // Directly access the view via its interface 
        if (this.myControl != null) 
            this.myControl.CallView("Hello From MyViewModel"); 
    } 
}

如果需要包含注入器附加属性源代码的可下载演示,请参见此博客文章。同时还请参阅此前问题,两者相关联。

此致敬礼,


谢谢,你的hacky解决方案给了我一个新思路,我也喜欢你的控制注入的想法,之前我也在考虑过。不过我已经得到了答案,请检查一下我在问题中的评论。非常感谢! - tzuhsun
1
@tzuhsun 没问题 - 很高兴你找到了答案! :) PS:来自MIT的黑客定义 - "对于一个本来不可能解决的问题的巧妙解决方案" - Dr. Andrew Burnett-Thompson

0

您需要绑定到ICommand的实现,并让其调用您的类方法。

这篇优秀的博客更详细地描述了如何使用ICommand从WPF执行代码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接