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