mshwf
mshwf

Reputation: 7449

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?

Upvotes: 4

Views: 9627

Answers (2)

Sharada
Sharada

Reputation: 13601

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);
}

Upvotes: 4

Yanbin Hu
Yanbin Hu

Reputation: 537

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();
}

Upvotes: 1

Related Questions