XJonOneX
XJonOneX

Reputation: 424

MAUI Community Toolkit EventToCommandBehavior

I'm desperately trying to adhere to the MVVM design pattern in my App. So I'm trying to use the EventToCommandBehavior behavior from the MCT. (I'm also using the CommunityToolkit.Mvvm for [RelayCommand]) I've attached it to an Entry and am trying to forward the TextChanged event to my command. However, my command doesn't execute.

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:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
             x:Class="MyApp.View.Accounts.AddAccountPage"
             xmlns:viewmodel="clr-namespace:MyApp.ViewModel.AccountsViewModel"
             Title="Add Account">
    <VerticalStackLayout>

        <Entry x:Name="entryAccountName"
               Placeholder="Account Name" 
               PlaceholderColor="Black"
               TextColor="{StaticResource Tertiary}"
               BackgroundColor="{StaticResource Primary}"
               WidthRequest="125"
               HorizontalOptions="Center"
               Keyboard="Text"
               ClearButtonVisibility="WhileEditing"
               ReturnType="Next">
            <Entry.Behaviors>
                <toolkit:EventToCommandBehavior
                        EventName="TextChanged"
                        Command="{Binding AccountTextChangedCommand}" />
            </Entry.Behaviors>
        </Entry>
....More XAML....

AccountsViewModel code:

    [RelayCommand]
    public void AccountTextChanged()
    {
        Application.Current.MainPage.DisplayAlert("Text changed", "Account Text Changed", "OK");
    }

I've got a breakpoint set to the Method and it just never gets called. Any ideas as to what am I doing wrong?

Upvotes: 1

Views: 4959

Answers (2)

ToolmakerSteve
ToolmakerSteve

Reputation: 21243

If by "reference in the header", you mean the line xmlns:viewmodel=...,
all that can do is declare a namespace that can be used in the following xaml. It can't refer to a class in that namespace - the line you show is ignored because it is not a valid namespace - you need:

<ContentPage 
  xmlns:viewmodel="clr-namespace:MyApp.ViewModel"  <--- NAMESPACE, NOT CLASS!
/>
<ContentPage.BindingContext>
  <viewmodel:AccountsViewModel/>
</ContentPage.BindingContext>

lines in your xaml, to say which viewmodel is the binding context. This is equivalent to the c# code you put in constructor.


OR There is an alternative technique, using Dependency Injection.

In MauiProgram.CreateMauiApp(), add lines similar to:

mauiAppBuilder.Services.AddTransient<MyApp.ViewModel.AccountsViewModel>();
mauiAppBuilder.Services.AddTransient<MyApp.View.Accounts.AddAccountPage>();

Exact details of those lines depend on your existing CreateMauiApp code, and your namespaces.

Upvotes: 2

XJonOneX
XJonOneX

Reputation: 424

I finally figured it out. I had forgotten to set the BindingContext to the AccountsViewModel in the constructor of the page:

using MyApp.Services;
using MyApp.ViewModel.AccountsViewModel;

namespace MyApp.View.Accounts;

public partial class AddAccountPage : ContentPage
{
    public AddAccountPage()
    {
        InitializeComponent();
        DataService dataService = new();
        AccountsViewModel accountsViewModel = new(dataService);
        BindingContext = accountsViewModel;
    }
}

I've been having to set the BindingContext via constructors on various pages to get the data bindings to work, even though I reference the ViewModels in the XAML header. Is this intended or am I going about it wrong?

Upvotes: 0

Related Questions