0

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?

XJonOneX
  • 305
  • 2
  • 11

2 Answers2

2

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.

ToolmakerSteve
  • 18,547
  • 14
  • 94
  • 196
  • 1
    Thank you for your explanation. I didn't realize I needed the ContentPage.BindingContext, this is all making much more sense now. – XJonOneX Oct 30 '22 at 20:13
0

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?

XJonOneX
  • 305
  • 2
  • 11