3

I need to bind a method to a custom control in xaml file, NOT the result of the method.

Basically the custom control will trigger the method few times when certain conditions match.

How can I do that?

I found some solutions in internet but most of them are binding the result of method into xaml, which is not the solution I looking for.

Many thanks.

tzuhsun
  • 91
  • 1
  • 7
  • Thanks ColinE and ChrisBD for quick responses! But I think command is not that suit to my case as we still neeed to trigger the command base on certain events in the custom control. However I found a solution which I going to share it below. – tzuhsun Jan 18 '12 at 08:50
  • Yeah I got the answer from here: http://stackoverflow.com/questions/5146946/binding-of-static-methode-function-to-funct-property-in-xaml/5156627#5156627. The question already is my answer. :) – tzuhsun Jan 18 '12 at 09:08

4 Answers4

2

There are two different approached which you can use:

  • Commands, expose a property of type ICommand which you bind to Command properties of your UI elements.
  • Use behaviours to wire a UI event to a method in your view model, for example use the MVVM Light EventToCommandBehaviour.
ColinE
  • 68,894
  • 15
  • 164
  • 232
2

Found this great answer:

Binding of static method/function to Func<T> property in XAML

Simon Rasmussen already shows all I need in his question sample code.

Community
  • 1
  • 1
tzuhsun
  • 91
  • 1
  • 7
1

Could you be more specific on what the conditions are? @ColineE and @ChrisBD correctly point out that ICommands and EventTocommandBehavior are going to help in many circumstances, such as translating a button click or a mouseover event into a method call in a ViewModel. I would advocate using these approaches if they can be used as they are deemed best practice

However, some cases require something a little more complex than that. One solution is to use code-behind to cast the DataContext to a view model type and invokle the method directly. For instance:

// 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();  
         }
    } 
}

This is considered a little hacky and pollutes the code-behind with knowledge of the ViewModel type at runtime. Something we want to avoid as it breaks the separation of concerns between View and ViewModel.

Another method is something I've used myself when dealing with a custom control that has little or no databinding support. By using an interface on the view and an attached property you can inject a view instance into the viewModel and manipulate it directly. Sort of a hybrid MVVM / MVP pattern which I've coined 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>

Code:

// 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"); 
    } 
}

For a downloadable demo including the source for the Injector attached property, please see this blog post. Also this previous question which is related.

Best regards,

Community
  • 1
  • 1
Dr. Andrew Burnett-Thompson
  • 20,980
  • 8
  • 88
  • 178
  • Thanks, you hacky solution give me new idea about my problem, also I like your idea of control injection which I thinking of it previously. However I got the answer, please check my comment in my question. Thanks a lot! – tzuhsun Jan 18 '12 at 09:11
  • 1
    @tzuhsun no problem at all - and glad you found your answer! :) PS: Definition of hack from MIT - "An ingenious solution to an otherwise impossible problem" – Dr. Andrew Burnett-Thompson Jan 18 '12 at 09:12
0

You'll be wanting to bind to an implementation of ICommand and have that call your class method.

Here's a good blog describing more about using ICommand to execute code from WPF.

ChrisBD
  • 9,104
  • 3
  • 22
  • 35