WPF: can I call a method from the xaml file that is in another class?

91 Views Asked by At

I am working on a WPF project, and I implemented the MVC -Pattern for my application . So I have the MainWindow.xaml and MainWindow.xaml.cs as the View, and then a Controller and a Model class (first time that I did this). Everything works great so far. But here is what i don't like: When I have an event defined in the xaml file, lets take:

<Button Content="Save" Click="SaveButton_ClickEvent"/>

then whenever the Save Button is clicked, the function in the xaml.cs file is called:

private void SaveButton_ClickEvent(object sender, RoutedEventArgs e)
{
    Controller.Save();
}

I actually have a lot of those functions in the xaml.cs file, where there is a function that just calls another fuction in the controller, and it seems kind of wasteful to me. Isn't there a better way of doing this? I think I have read somewhere that if one implements the MVC-pattern in WPF, the xaml.cs file stays almost empty. So my question is:

Is there a way to call a Method in my controller (or any other) class from within the .xaml file wihtout putting a function in the xaml.cs file? (and if yes, how would i do that)

Or did I get it all wrong and this is all done differently?

1

There are 1 best solutions below

1
mm8 On BEST ANSWER

If you don't want to implement the recommended MVVM design pattern and replace the event handler with a binding that binds the Command property of the Button to an ICommand property of a view model, you could for example implement an attached behaviour that handles the Click event and calls your controller:

public static class Mvc
{
    public static readonly DependencyProperty ClickProperty =
        DependencyProperty.RegisterAttached(
            "Click", typeof(string), typeof(Mvc),
            new PropertyMetadata(string.Empty, OnChanged));

    public static string GetClick(Button obj) =>
        (string)obj.GetValue(ClickProperty);

    public static void SetClick(Button obj, string value) =>
        obj.SetValue(ClickProperty, value);

    private static void OnChanged(
        DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        if (!string.IsNullOrEmpty(e.NewValue as string)
            && obj is Button button)
        {
            button.Click += OnButtonClick;
        }
    }

    private static void OnButtonClick(object sender, RoutedEventArgs e)
    {
        Button button = (Button)sender;
        object controller = button.DataContext;
        if (controller != null)
        {
            string methodName = GetClick(button);
            if (!string.IsNullOrEmpty(methodName))
            {
                controller.GetType()
                    .GetMethod(methodName)?
                    .Invoke(controller, null);
            }
        }
    }
}

XAML:

<Button Content="Save" local:Mvc.Click="Save"/>

Code-behind:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new Controller();
    }
}

Controller:

public class Controller
{
    public void Save()
    { 
        //save... 
    }
}