Home > Software engineering >  How to provide Command-Property for custom control in MVVM (.NET MAUI)
How to provide Command-Property for custom control in MVVM (.NET MAUI)

Time:08-10

I'm trying to build a custom control in .NET MAUI, that should provide an BindableProperty of ICommand for its parent. Here is a basic example for what i try to achieve.

MainPage View (MainPage.xaml)

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:views="clr-namespace:SampleApp.Views"
             x:Class="SampleApp.MainPage">

    <views:MyCustomControl DoSomething="{Binding DoSomethingCommand}"></views:MyCustomControl>
</ContentPage>

MainPage View Class (MainPage.xaml.cs)

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
        BindingContext = new MainPageViewModel();
    }
}

MainPage View Model (MainPageViewModel.cs)

public class MainPageViewModel : ObservableObject
{
    public ICommand ProcessNewScoreCommand { get; }

    public MainPageViewModel()
    {
        ProcessNewScoreCommand = new Command(DoSomething);
    }

    private void DoSomething()
    {
        // Do something
    }
}

MyCustomControl View Class (MyCustomControl.xaml.cs)

public partial class MyCustomControl : ContentView
{
    public static readonly BindableProperty DoSomethingProperty =
        BindableProperty.Create(nameof(DoSomething), typeof(ICommand), typeof(MyCustomControl));

    public ICommand DoSomething
    {
        get => (ICommand)GetValue(DoSomethingProperty);
        set => SetValue(DoSomethingProperty, value);
    }

    public MyCustomControl()
    {
        InitializeComponent();
        BindingContext = new MyCustomControlViewModel(DoSomething);
    }
}

MyCustomControl View-Model (MyCustomControlViewModel.cs)

public class MyCustomControlViewModel : ObservableObject
{
    public ICommand DoSomething { get; }

    public MyCustomControlViewModel(ICommand doSomethingCommand)
    {
        DoSomething = doSomethingCommand;
    }

    private void PerformSomeLogic()
    {
        // Any calulations/logic
        // ...

        if (DoSomething.CanExecute(null))
        {
            // Execute command, so that parent component gets informed and can act.
            DoSomething.Execute(null);
        }
    }
}

While debugging, the Property DoSomething of class MyCustomControl.xaml.cs is always null. Also it seems, that its setter isn't called at any time. What am I doing wrong?

CodePudding user response:

The reason it's not working is that you are creating a VM for your custom control i.e. the view then assigning it a context and then later on in your custom control you are changing its BindingContext all over again, Custom Controls should not have their own predefined BC.

Steps to fix this:

  • Remove your MyCustomControlViewModel class.

  • Now your CustomControl.xaml.cs would look like this:

    public partial class MyCustomControl : ContentView
    {
    
      public static readonly BindableProperty DoSomethingProperty =
                    BindableProperty.Create(nameof(DoSomething), typeof(ICommand), typeof(MyCustomControl));
    
      public ICommand DoSomething
      {
          get => (ICommand)GetValue(DoSomethingProperty);
          set => SetValue(DoSomethingProperty, value);
      }
    
      public MyCustomControl()
      {
          InitializeComponent();
      }
    }
    
  • Now your View's VM should be the one that handles the logic so you don't have multiple BindingContext's confusing and the compiler(By searching it in the wrong place):

    public class MainPageViewModel : ObservableObject {

      public ICommand DoSomething { get; }
    
     public MainPageViewModel()
     {
        DoSomething = new Command(DoSomething);
     }
    

Good luck, let me know if there is some other questions you have.

A basic guide to MVVM with XF and MAUI: https://docs.microsoft.com/en-us/xamarin/xamarin-forms/xaml/xaml-basics/data-bindings-to-mvvm

  • Related