Sam
Sam

Reputation: 30388

Binding Button Command in ContentView to Parent's ViewModel in .NET MAUI app

I'm trying to create a reusable ContentView in my .NET MAUI app that needs to call a method in parent's view model.

Something like this:

<ContentPage
   xmlns:vm="MyApp.ViewModels"
   xmlns:control="MyApp.Views.Controls"
   x:DataType="vm:MyViewModel">
   <Grid
      RowDefinitions="50,50, *">

      <control:MyContentView Grid.Row="0" />
      ...
   </Grid>
</ContentPage>

Here's the ContentView code:

<ContentView
   xmlns:model="MyApp.Models.MyModel">
   <Button
      Text="Do Something"
      Command="{Binding DoSomethingCommand} />
</ContentView>

Here's the ViewModel code:

public partial class MyViewModel : BaseViewModel
{
   ...
   [RelayCommand]
   async Task DoSomething()
   {
      // Business logic here...
   }
}

Two questions:

  1. How do I call the method in parent content page's view model from the ContentView?
  2. Since, I'm trying to make this ContentView reusable, I want to be able to use it in another ContentPage which will have its own view model. I can make sure the method names match but is it possible to not tightly couple the binding for the Button in the ContentView with a specific view model?

Upvotes: 2

Views: 3699

Answers (1)

Jessie Zhang -MSFT
Jessie Zhang -MSFT

Reputation: 13803

How do I call the method in parent content page's view model from the ContentView?

One problem, one thread. I will answer the first problem.

You can add a Bindable Property in your ContentView. Let's say your view is named ChildView.

Then you can refer to the following code:

ChildView.xaml

Here, TestControlView is the x:Name property of current ContentView.

<?xml version="1.0" encoding="utf-8" ?> 
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiContentViewApp.ChildView"
             x:Name="TestControlView">
    <VerticalStackLayout>
      
        <Button Text="Do Something"
                Command="{Binding Source={x:Reference TestControlView}, Path= ChildCommand}" />
    </VerticalStackLayout>
</ContentView>

ChildView.xaml.cs

public partial class ChildView : ContentView 
{
    // add ChildCommandProperty here 
    public static readonly BindableProperty ChildCommandProperty =
            BindableProperty.Create(nameof(ChildCommand), typeof(ICommand), typeof(ChildView));
    
    public ICommand ChildCommand
    {
        get => (ICommand)GetValue(ChildCommandProperty);
        set => SetValue(ChildCommandProperty, value);
    }
    
    public ChildView()
    {
        InitializeComponent();
    }
}

Usage example:

<?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:mauiapp="clr-namespace:MauiContentViewApp"
             x:Class="MauiContentViewApp.MainPage"
             x:Name="mainpage">
    <ContentPage.BindingContext>
        <mauiapp:MyViewModel></mauiapp:MyViewModel>
    </ContentPage.BindingContext>
    
    <ScrollView>
        <VerticalStackLayout>
    
            <mauiapp:ChildView 
                   ChildCommand="{Binding DoSomethingCommand}" >
    
            </mauiapp:ChildView>
   
        </VerticalStackLayout>
    </ScrollView>
</ContentPage>

MyViewModel.cs

public class MyViewModel
{
    public ICommand DoSomethingCommand => new Command(doSomethingMethod);

    private void doSomethingMethod(object obj)
    {
        System.Diagnostics.Debug.Write("invoke command  dosomething");
    }
}

Upvotes: 2

Related Questions