I'm developing a mobile app using .Net MAUI and having trouble with data binding in XAML. I have MainPage.xaml
that receives data from MainPageViewModel.cs
which inherits from ObservableObject
.
In Flyout.cs
, I have Title
, IconSource
, and Command
and get them in <DataTemplate>
in Mainpage.xaml
. I pass values to each of the property in <CollectionView.ItemSource>
and only to Command
, I am passing a string of method that is defined in MainPageViewModel.xaml.cs
.
I am confused about how to perform data binding here.
Values for Title
and IconSource
are bound correctly and visible, but only Command
is not working.
How can I get this to work?
MainPage.xaml:
<?xml version="1.0" encoding="utf-8" ?>
<FlyoutPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:vm="clr-namespace:Realizer.ViewModels"
xmlns:models="clr-namespace:Realizer.Models"
xmlns:local="clr-namespace:Realizer.Pages"
x:Class="Realizer.Pages.MainPage"
x:DataType="vm:MainPageViewModel"
Title="Home">
<FlyoutPage.Flyout>
<ContentPage Title="Home page" BackgroundColor="LightGrey">
<VerticalStackLayout>
<CollectionView>
<CollectionView.ItemsSource>
<x:Array Type="{x:Type models:Flyout}">
<models:Flyout Title="Home"
IconSource="home.png"
Command="{Binding GoHomeCommand}"/>
<models:Flyout Title="Clients"
IconSource="person.png"
Command="{Binding GoToClientsPageCommand}"/>
<models:Flyout Title="Products"
IconSource="medicine_bag.png"
Command="{Binding GotoProductsPageCommand}"/>
</x:Array>
</CollectionView.ItemsSource>
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="20, 5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Source="{Binding IconSource, Source={RelativeSource AncestorType={x:Type models:Flyout}}}"
Scale="1.5"/>
<Button Grid.Column="1"
Margin="5"
Text="{Binding Title, Source={RelativeSource AncestorType={x:Type models:Flyout}}}"
Command="{Binding Command,Source={RelativeSource AncestorType={x:Type models:Flyout}}}"
FontSize="16"
FontAttributes="Bold"
TextColor="Black"
HeightRequest="60"
Padding="0,0,110,0"
BackgroundColor="ForestGreen"/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<Label Text="this is it"
Margin="20"/>
</VerticalStackLayout>
</ContentPage>
</FlyoutPage.Flyout>
<FlyoutPage.Detail>
<NavigationPage BarBackgroundColor="Navy"
BarTextColor="Black"
Title="Home">
<x:Arguments>
<ContentPage Title="Home" BackgroundColor="White">
<VerticalStackLayout>
<Label Text="this is detail"
Margin="20"/>
</VerticalStackLayout>
</ContentPage>
</x:Arguments>
</NavigationPage>
</FlyoutPage.Detail>
</FlyoutPage>
MainPage.xaml.cs:
using Realizer.ViewModels;
namespace Realizer.Pages;
public partial class MainPage : FlyoutPage
{
public MainPage(MainPageViewModel viewModel) {
InitializeComponent();
BindingContext = viewModel;
}
}
MainPageViewModel.cs
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
namespace Realizer.ViewModels
{
public partial class MainPageViewModel : ObservableObject
{
public MainPageViewModel()
{
}
[RelayCommand]
private void GoToClientsPage()
{
Console.WriteLine("hi");
}
[RelayCommand]
private void GoHome()
{
Console.WriteLine("hi home");
}
[RelayCommand]
private void GoToProductsPage()
{
Console.WriteLine("hi pro");
}
}
}
Flyout.cs
namespace Realizer.Models
{
internal class Flyout
{
public string Title { get; set; }
public string IconSource { get; set; }
public string Command { get; set; }
}
}
MauiProgram.cs
builder.Services.AddSingleton<MainPage>();
builder.Services.AddSingleton<MainPageViewModel>();
I referred to this tutorial when writing the code.
I tried Command="{Binding GoHomeCommand, Source={RelativeSource AncestorType={x:Type vm:MainPageViewModel}}}}"/>
, but I am not even sure what I'm doing here.
Instead of figuring out the data type, I made a "OnClick" method in "MainPageViewModel.cs", called it in <Button>
in <DataTemplate>
in "MainPage.xaml", and deleted each "Command" property in <model:flyout>
.
MainPageViewModel.cs
:
[RelayCommand]
private async void OnClick(string page){
if(page == "Home") ...//page navigation here
else if (page == "Clients")...
}
MainPage.xaml
:
<DataTemplate>
...
<Button Grid.Column="1"
Margin="5"
Text="{Binding Title, Source={RelativeSource AncestorType={x:Type models:Flyout}}}"
Command="{Binding ClickCommand, Source={RelativeSource AncestorType={x:Type vm:MainPageViewModel}}}"
CommandParameter="{Binding Title, Source={RelativeSource AncestorType={x:Type models:Flyout}}}"/>
...
</DataTemplate>