0
votes

Binding command to a Button - yields no effect (Xamarin, MVVM):

notes:

  • Pressing the Button and nothing happens: no CanExecute check occur.
  • Binding a Button in a ContentPage which is Part of a Tabbed-Template
  • functionality check and the rest of related MVVM binding works well: Defined a clicked-event and manually triggered the command from the code behind.

//Could someone see the reason?// editted editted, new: What would be a good practice when CanExecute relies on fields of a compound data type that are updated independently ? (*can take of the command parameter which is the compound data type, which is accessible to the command directly through the VM).

xaml for the View:

    <ContentPage.Content>
    <StackLayout>
        <Entry Placeholder="Notes"/>
        <Entry x:Name="courseIDEntry" 
               Text="{Binding CourseID, Mode=TwoWay}"
               IsReadOnly="{Binding !ExistUnit}"
               Placeholder="CourseID *"/>
        <Entry x:Name="unitIDEntry" 
               Text="{Binding UnitID, Mode=TwoWay}"
               IsReadOnly="{Binding !ExistUnit}"
               Placeholder="UnitID *"/>enter code here
        <Label Text="* Fields are mandatory"/>
        <Button x:Name="AddSave"
            Text="{Binding CommandText}" 
            Command="{Binding AddSaveCMD}"    
            CommandParameter="{Binding EdittedUnit}"/>
            <!--Clicked="AddSave_Clicked"/>--> 
    </StackLayout>
</ContentPage.Content>enter code here

c# code behind for the view (*including the Button-Clicked check for)

public partial class EditUnitPage : ContentPage
{
    EditUnitViewModel editUVM;

    public EditUnitPage()
    {
        InitializeComponent();

        editUVM = new EditUnitViewModel();
        BindingContext = editUVM;
    }

    public EditUnitPage(Unit6 unitSelected) : this()
    {
        if (unitSelected != null)
        {
            editUVM.EdittedUnit = unitSelected; 
            editUVM.ExistUnit = true;
        }
    }
    protected override void OnAppearing()
    {
        base.OnAppearing();
    }

    //private void AddSave_Clicked(object sender, EventArgs e)
    //{
    //    if (editUVM.AddSaveCMD.CanExecute(editUVM.EdittedUnit))
    //    {
    //        editUVM.AddSaveCMD.Execute(null);
    //    }
    //}
}       

C# MyCommand (newbie. using ICommand and not the Command Class)

public class AddSaveUnitCommand : ICommand
{
    public EditUnitViewModel EditUVM { get; set; }


    public event EventHandler CanExecuteChanged;

    public AddSaveUnitCommand(EditUnitViewModel euvm)
    {
       EditUVM = euvm;
    }

    public bool CanExecute(object parameter)
    {
        var editted = parameter as Unit6;

        if (editted != null )
        {
            if (!string.IsNullOrEmpty(editted.CourseID) || !string.IsNullOrEmpty(editted.UnitID))
                return true;
        }
        return false;
    }

    public void Execute(object parameterf)
    {
        EditUVM.AddSaveUnitAsync();
    }
}

c# for VM (BaseViewModel implements INotify)

public class EditUnitViewModel : BaseViewModel
{
    public AddSaveUnitCommand AddSaveCMD { get; set;  }

    private Unit6 edittedUnit;
    public Unit6 EdittedUnit
    {
        get { return edittedUnit; }
        set { edittedUnit = value; OnPropertyChanged(); }
    }

    private bool existUnit;
    public bool ExistUnit
    {
        get { return existUnit; }
        set 
        { 
            existUnit = value;
            //OnPropertyChanged(); 
        }
    }

    public string CommandText
    {
        get { return ExistUnit? "Save": "Add"; }
    }

    public string CourseID
    {
        get { return EdittedUnit.CourseID; }
        set { EdittedUnit.CourseID = value; OnPropertyChanged(); }
    }

    public string UnitID
    {
        get { return EdittedUnit.UnitID; }
        set { EdittedUnit.UnitID = value; OnPropertyChanged(); }
    }

    public EditUnitViewModel()
    {
        EdittedUnit = new Unit6();
        AddSaveCMD = new AddSaveUnitCommand(this);
    }

    public async void AddSaveUnitAsync()
    {
        var curPage = App.Current.MainPage;
        try
        {
            switch (ExistUnit)
            {
                case false: //insert new unit to the DB
                    EdittedUnit.UnitKey = ""; //Todo: look for more elegant of assigning auto value to property
                    Unit6.Insert(EdittedUnit);
                    break;
                case true: //update details on existing unit
                    EdittedUnit.UnitKey = ""; //Todo: look for more elegant of assigning auto value to property
                    Unit6.Update(EdittedUnit);
                    break;
            }
            await curPage.DisplayAlert("Success", "Unit was succesffuly updateded", "OK");
        }
        catch
        {
            await curPage.DisplayAlert("Error", "Unit was not updated", "OK");
        }
        finally
        {
            EdittedUnit = null;
            await curPage.Navigation.PushAsync(new MyTabbedPage());
        } 
    }
}

xaml for the TabbedPage:

<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
        xmlns:views="clr-namespace:P205.Views"
        x:Class="P205.Views.MyTabbedPage">

<views:UnitsPage Title="Units" />
<views:EditUnitPage x:Name="editOrAddUnit" Title="Edit U"/>
<views:DBChangesPage Title="Edit DB"/>
<views:CoursesPage Title="Course"/> 

<ContentPage Padding="10">
    
</ContentPage>
1

1 Answers

0
votes

When your ViewModel defines a property of type ICommand, the ViewModel must also contain or reference a class that implements the ICommand interface. This class must contain or reference the Execute and CanExecute methods, and fire the CanExecuteChanged event whenever the CanExecute method might return a different value.

So you could try change like below:

public class AddSaveUnitCommand : ICommand
{
   public EditUnitViewModel EditUVM { get; set; }


   public event EventHandler CanExecuteChanged;

   public AddSaveUnitCommand(EditUnitViewModel euvm)
   {
   EditUVM = euvm;
   }

   public bool CanExecute(object parameter)
   {
      var editted = parameter as Unit6;

      if (editted != null )
      {
         if (!string.IsNullOrEmpty(editted.CourseID) || !string.IsNullOrEmpty(editted.UnitID))
            return true;
      }
      return false;
   }

  public void Execute(object parameterf)
  {
     EditUVM.AddSaveUnitAsync();
     CanExecuteChanged?.Invoke(this, EventArgs.Empty); //add this line.
  }
}