xamarin binding a button in code to viewModel (without xaml)

I'm using the mvvm approach to develop a barcode scanning app with xamarin. The main hurdle was that the 3rd party scanner object does not work in xaml. I used a ContentPage to create a simple logic-less c# code view which allows me to have a footer with buttons and a logo overlayed at the bottom of the scanner. My problem is that could not find any great best practices for binding items from your code view to your viewModel, as opposed binding a xaml view to a viewModel. Here is some of my view below.

    public class BarcodeScannerPage : ContentPage
        {
            ZXingScannerView zxing;
            BarcodeViewModel viewModel;

            public BarcodeScannerPage() : base()
            {
                try
                {
                    viewModel = new BarcodeViewModel();
                    BindingContext = viewModel;

                    zxing = new ZXingScannerView
                    {
                        HorizontalOptions = LayoutOptions.FillAndExpand,
                        VerticalOptions = LayoutOptions.FillAndExpand,
                        Options = new MobileBarcodeScanningOptions
                        {
                            TryHarder = true,
                            DelayBetweenContinuousScans = 3000
                        },
                        ScanResultCommand = viewModel.GetResult
                    };

                    var cancelButton = new Button
                    {
                        BackgroundColor = Color.Gray,
                        Text = "Cancel",
                        TextColor = Color.Blue,
                        FontSize = 15,
                        Command = viewModel.CancelButton
                    };

                    Binding cancelBinding = new Binding
                    {
                        Source = viewModel.CancelIsAvailable,
                        //Path = "ShowCancel",
                        Mode = BindingMode.OneWay,
                    };
                    cancelButton.SetBinding(IsVisibleProperty, cancelBinding);

                    var doneButton = new Button
                    {
                        BackgroundColor = Color.Gray,
                        Text = "Done",
                        TextColor = Color.Blue,
                        FontSize = 15,
                        Command = viewModel.DoneButton
                    };

                    Binding doneBinding = new Binding
                    {
                        Source = viewModel.DoneIsAvailable,
                        //Path = "ShowDone",
                        Mode = BindingMode.OneWay,
                    };
                    doneButton.SetBinding(Button.IsVisibleProperty, doneBinding);

When a barcode is scanned my command, GetResultCommand, sends the result to my BarcodeView model. I have created two Bools in my BarcodeView model named isDoneAvailable and isCancelAvailable. I want to bind these values to the Visibility property of the doneButton and cancelButton in my view. Right now the buttons are bound to whatever the bool values are at the creation of BarcodeViewModel, but they DO NOT update. I need to be able to control visibility from the GetResultCommand method of my BarcodeViewModel. Specifically, when a certain number of barcodes are scanned, I want to make the buttons appear and disappear. I have a feeling they don't update because the path is not set, but when I uncomment the path, the binding doesn't work at all. Any ideas what I've done wrong with the bindings of the buttons, or the correct way to set the Path to my bools in the viewModel? Here is some of my BarcodeViewModel code below.

public class BarcodeViewModel : INotifyPropertyChanged
    {
public bool CancelIsAvailable { get { return _cancelIsAvailable; } set { _cancelIsAvailable = value; OnPropertyChanged("ShowCancel"); } }

public bool DoneIsAvailable { get { return _doneIsAvailable; } set { _doneIsAvailable = value; OnPropertyChanged("ShowDone"); } }

public void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this,
                    new PropertyChangedEventArgs(propertyName));
            }
        }

Answers

  • I still would like to know the correct way to get this binding to update but, I was able to work-around this issue by creating a button in my viewModel and referencing it in my view. Then when I dynamically updated the button in my viewModel, it also updated in my view.

Sign In or Register to comment.