Bind an Action to a property of a UserControl in XAML

windows-runtime, winrt-xaml

Solution

The issue is in your data binding. The `Action1` in `ButtonAction="{Binding Action1}"` should be a public property while you defined it as a private variable.

Also, you cannot just declare a normal property directly in the code behind like that. You will need either a dependency property, or more commonly, a public property inside a viewmodel which implements `INotifyPropertyChanged`.

If we go with the second approach, we will need to create a viewmodel class like the following with an `Action1` property. Note the `OnPropertyChanged` stuff is just the standard way of implementing `INotifyPropertyChanged`.

public class ViewModel : INotifyPropertyChanged
{
    private Action _action1;
    public Action Action1
    {
        get { return _action1; }
        set
        {
            _action1 = value;
            OnPropertyChanged("Action1");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string name)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
}

And then you just need to assign this to the `DataContext` of your main page.

    public MainPage()
    {
        this.InitializeComponent();

        var vm = new ViewModel();
        vm.Action1 = (() =>
        {
            Debug.WriteLine("Action1 called");
        });

        this.DataContext = vm;
    }

With these two changes, your `ButtonAction` callback should be firing now. :)

Problem

I have a user control which has a button and a dependency property for the action the button is to execute. The page which contains the control sets the action in XAML. MyUserControl.cs A Button, and dependency property `ButtonAction`, of type `Action`. When the button is clicked it executes the `ButtonAction`. MainPage.xaml.cs Action Action1 Action Action2 MainPage.xaml Present an instance of `MyUserControl`, with ButtonAction=Action1 The problem: The ButtonAction property is not assigned from the XAML MyUserControl.cs ``` public sealed partial class MyUserControl : UserControl { public Action ButtonAction { get { return (Action)GetValue(ButtonActionProperty); } set { SetValue(ButtonActionProperty, value); } } public static readonly DependencyProperty ButtonActionProperty = DependencyProperty.Register("ButtonAction", typeof(Action), typeof(MyUserControl), new PropertyMetadata(null,ButtonAction_PropertyChanged)); private static void ButtonAction_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Debug.WriteLine("ButtonAction_PropertyChanged"); // Is not called! } public MyUserControl() { this.InitializeComponent(); } private void Button_Click(object sender, RoutedEventArgs e) { if (ButtonAction != null) { // Never reaches here! ButtonAction(); } } } ``` MyUserControl.xaml ``` <Grid> <Button Click="Button_Click">Do The Attached Action!</Button> </Grid> ``` MainPage.xaml.cs ``` Action Action1 = ( () => { Debug.WriteLine("Action1 called"); }); Action Action2 = (() => { Debug.WriteLine("Action2 called"); }); ``` MainPage.xaml ``` <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <local:MyUserControl x:Name="myUserControl" ButtonAction="{Binding Action1}"/> </Grid> ``` It does work if in the code-behind for MainPage (`MainPage.xaml.cs`) I assign the action in the `Loaded` event. ``` private void Page_Loaded(object sender, RoutedEventArgs e) { this.myUserControl.ButtonAction = Action1; } ``` In this case the PropertyChanged callback in the user control is also called. (This handler is provided only for diagnostic purposes. I can't see how it can be used to support the property in practice).

Original source