Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bind Entry TextChanged to the CanExecute method of button command in Xamarin.Forms

I want to disable the send button if any of the three entries is empty, but how that can be achieved in an MVVM fashion?

I thought of the CanExecute delegate, but how can I fire it whenever the TextChanged fired?

Also if I opt in the behaviors, how can I communicate with other controls like button if I'm using Behavior<Entry>

This is the view:

<ContentPage.Content>
    <AbsoluteLayout>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="20"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="56"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="30"/>
                <RowDefinition Height="10"/>
                <RowDefinition Height="30"/>
                <RowDefinition Height="30"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="50"/>
            </Grid.RowDefinitions>
            <Label Text="Contact Us" FontSize="Medium" Grid.ColumnSpan="3"/>
            <Entry Text="{Binding ContactData.message_name}" x:Name="subject" Grid.Row="2" Grid.Column="1" Placeholder="Subject"/>
            <Entry Keyboard="Email" Text="{Binding ContactData.receiver_email}" x:Name="email" Grid.Row="3" Grid.Column="1" Placeholder="Email"/>
            <Editor Text="{Binding ContactData.message_subject}" x:Name="body" Grid.Row="4" Grid.Column="1" />

            <Button Grid.Row="5" Grid.Column="1" Command="{Binding ContactFormSent}" Text="Send"/>
        </Grid>
    </AbsoluteLayout>
</ContentPage.Content>

in the ViewModel:

public ContactViewModel()
{
    ContactFormSent = new RelayCommand(SendContactInfo);
    ContactData = new ContactModel();
}

private bool CanSend() //this only get called when the view model is constructed
{
    return !(string.IsNullOrWhiteSpace(ContactData.receiver_email) && string.IsNullOrWhiteSpace(ContactData.message_subject) &&
        string.IsNullOrWhiteSpace(ContactData.message_name));
}

In the Behavior option, I wan it to be used with both Entry and Editor, so is my way to go is the Behavior class, not the generic version? if so, then how can I implement it?

like image 404
mshwf Avatar asked Oct 12 '25 07:10

mshwf


2 Answers

Usually, in order to react to a view event using MVVM pattern, it is recommended that you use EventToCommandBehaviour.

But in this case it is not needed, as the setters on properties bound to Entry should trigger every time text changes. You can use that to trigger ChangeCanExecute() on command to notify view that the button can now be enabled/disabled.

For e.g.:

string _firstName;
public string FirstName
{
    get { return _firstName; }
    set
    {
        if (_firstName != value)
            SendCommand.ChangeCanExecute();
        SetProperty(ref _firstName, value, nameof(FirstName));
    }
}

string _lastName;
public string LastName
{
    get { return _lastName; }
    set
    {
        if (_lastName != value)
            SendCommand.ChangeCanExecute();
        SetProperty(ref _lastName, value, nameof(LastName));
    }
}

string _email;
public string Email
{
    get { return _email; }
    set
    {
        if (_email != value)
            SendCommand.ChangeCanExecute();
        SetProperty(ref _email, value, nameof(Email));
    }
}

Command _sendCommand;
public Command SendCommand 
{
    get
    {
        return _sendCommand ?? (_sendCommand = new Command(OnSend, CanSend));
    }    
}

bool CanSend(object obj)
{
    return Validate();
}

void OnSend(object obj)
{
    if(Validate())
    {
        //actual button click execution
    }
}

bool Validate()
{
    // disable button if any entry empty
    return !string.IsNullOrEmpty(_firstName)
                  && !string.IsNullOrEmpty(_lastName)
                  && !string.IsNullOrEmpty(_email);
}
like image 130
Sharada Gururaj Avatar answered Oct 13 '25 22:10

Sharada Gururaj


Command has a public method ChangeCanExecute(). When you new a Command, you could specify the canExecute condition. Once your TextChanged event is triggered, call the ChangeCanExecute() method.

Example:

Command someCommand = new Command(
 () => SomeMethod(),
 ()=> { return CanSend(); }
);

Once a Button changed a text:

private void TextChanged(object sender, TextChangedEventArgs e)
{
    ViewModel.someCommand.ChangeCanExecute();
}
like image 28
Yanbin Hu Avatar answered Oct 14 '25 00:10

Yanbin Hu



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!