0

I am new using .NET MAUI and my issue is very simple but I could not find a way to solve this, I am trying to get any component by its x:Name using Mvvm pattern.

is it possible through ViewModels? For example I have a login page after clicking button I want this button to get blocked to prevent double clicks.

Login.xaml

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         x:Class="Ventas_Citel.Views.Login.Login"
         xmlns:viewmodel="clr-namespace:Sales.ViewModels.Login"
         Title="">
<VerticalStackLayout 
   //... login page xaml form ...
   
    <Button Text="Log In" WidthRequest="200" CornerRadius="5" HorizontalOptions="Center" Command="{Binding LoginCommand}" x:Name="loginButton"/>

   //... login page xaml form ...
</VerticalStackLayout>

Login.xaml.cs

 using CommunityToolkit.Mvvm.ComponentModel;
 using CommunityToolkit.Mvvm.Input;
 using CommunityToolkit.Maui.Alerts;
public partial class Login : ContentPage
{
    public Login(LoginViewModel viewModel)
    {
        InitializeComponent();
        BindingContext = viewModel;
    }
}

loginViewModel

 public partial class LoginViewModel : ObservableObject
    {
        [RelayCommand]
        async void Login()
        {
            if (!string.IsNullOrWhiteSpace(Email) && !string.IsNullOrWhiteSpace(Password))
            {

                // is there a way to call loginButton component?????
               // i need to disable it with loginButton.IsEnable = false;
                 loginButton.IsEnable = false // doesnt work loginButton doesnt exist

               // if there is any error i need to enable it again so the user can re enter
               // his/her credentials if it fails
                  loginButton.IsEnable = true;
            }

        }

}

How do I solve this?

Reyneer Leon
  • 356
  • 2
  • 14
  • 1
    Your `loginButton` is part of the page, not the view model. In `Login.xaml.cs` you could refer to `loginButton`. If your view model sends events to the view, you could listen and have the view toggle the button depending on the status of the view model. – Ibrennan208 Nov 17 '22 at 05:21
  • Why do you need this, may be i can help you with that – FreakyAli Nov 17 '22 at 05:42
  • @FreakyAli well this is a part of my learning process using mvvm there are situations where I need to manipulate components like setting colours, settings states ( enabled, disabled), hide elements, etc but using mvvm. So I have no idea what Im doing, I need to see how you achieve this. – Reyneer Leon Nov 17 '22 at 05:49
  • If that is the case usually this is done using properties that expose your state and Converters and Styles that make changes to your controls based on changes to your property – FreakyAli Nov 17 '22 at 06:14
  • do you mean by using `[ObservableProperty]`? – Reyneer Leon Nov 17 '22 at 07:04

2 Answers2

2

To solve this in correct MVVM manner, you have to add an additional property (for example IsLoginButtonEnabled) to your view model and just bind the button's IsEnabled property to it

ViewModel

public partial class LoginViewModel : ObservableObject
{
  private bool _isLoginButtonEnabled;
  public bool IsLoginButtonEnabled
  {
    get => _isLoginButtonEnabled;
    set
    {
       _isLoginButtonEnabled = value;
       PropertyChanged?.Invoke( this, new PropertyChangedEventArgs( "IsLoginButtonEnabled" ) );
    }
  }

  [RelayCommand]
  async void Login()
  {
    if (!string.IsNullOrWhiteSpace(Email) && !string.IsNullOrWhiteSpace(Password))
    {
      this.IsLoginButtonEnabled = false;

      // if there is any error i need to enable it again so the user can re enter
      // his/her credentials if it fails
      
      // In order to enable the button again, just call ...
      //this.IsLoginButtonEnabled = true;
    }
  }
}

View

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
     xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
     x:Class="Ventas_Citel.Views.Login.Login"
     xmlns:viewmodel="clr-namespace:Sales.ViewModels.Login"
     Title="">
<VerticalStackLayout 
   //... login page xaml form ...

  <Button Text="Log In" Command="{Binding LoginCommand}" IsEnabled="{Binding IsLoginButtonEnabled}" />

  //... login page xaml form ...
</VerticalStackLayout>
Sandman
  • 302
  • 2
  • 14
0

I want to say something about your code:

  1. Do not try to access View elements in your ViewModel. Use bindings instead.

  2. If you gonna bind enabled, do not name the property for specific button. You don't want to handle it separately for each VisualElement. (Check out Value Convertors for reversal bool)

  3. This "isNullOrEmpty", can easily be replaced by TextValidationBehavior. And bind all this to a single bool. So you don't have to chain too many AND checks.

H.A.H.
  • 2,104
  • 1
  • 8
  • 21