Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatically click a button in Xamarin.Forms

I have 2 buttons on a xamarin form,

scannerButton and checkOrderButton

scannerButton opens the scanner page, scans a QRCode and populates it into a order entry field

checkOrderButton reads whatever is in the order entry field and processes validations and sends it to server for verification

what I want - is to call the checkOrderButton.Click from within the scannerButton.Click - after it has scanned the text

code:

private async void scanCameraButton_Clicked(object sender, EventArgs e)
{
    var options = new ZXing.Mobile.MobileBarcodeScanningOptions();
    options.PossibleFormats = new List<ZXing.BarcodeFormat>() {
        ZXing.BarcodeFormat.QR_CODE,ZXing.BarcodeFormat.EAN_8, ZXing.BarcodeFormat.EAN_13
    };

    var scanPage = new ZXingScannerPage(options);
    scanPage.OnScanResult += (result) =>
    {
        //stop scan
        scanPage.IsScanning = false;

        Device.BeginInvokeOnMainThread(() =>
        {
            //pop the page and get the result
            Navigation.PopAsync();
            orderNoEntry.Text = result.Text;
        });

            //invoke checkOrderButton.Click here

    };

what would be the best approach to do this?

one alternate is to dump all the functionality from checkOrderButton.Click handler into a function and then call that function from both button clicks, but I'm interested in learning how I can invoke the click event programmatically

like image 910
Danish Avatar asked Mar 10 '23 10:03

Danish


2 Answers

I wrote an extension method for this purposes. This not only works in Xamarin-Forms-projects but also in WPF projects.

using System;
using System.Reflection;
using System.Windows;
using System.Windows.Input;
#if !NETSTANDARD
using System.Windows.Controls;
#else
using Xamarin.Forms;
#endif

public static class ButtonExtensions
{
    public static void PerformClick(this Button sourceButton)
    {
        // Check parameters
        if (sourceButton == null)
            throw new ArgumentNullException(nameof(sourceButton));

        // 1.) Raise the Click-event
#if !NETSTANDARD
        sourceButton.RaiseEvent(new RoutedEventArgs(System.Windows.Controls.Primitives.ButtonBase.ClickEvent));
#else
        sourceButton.RaiseEventViaReflection(nameof(sourceButton.Clicked), EventArgs.Empty);
#endif

        // 2.) Execute the command, if bound and can be executed
        ICommand boundCommand = sourceButton.Command;
        if (boundCommand != null)
        {
            object parameter = sourceButton.CommandParameter;
            if (boundCommand.CanExecute(parameter) == true)
                boundCommand.Execute(parameter);
        }
    }

#if NETSTD
    private static void RaiseEventViaReflection<TEventArgs>(this object source, string eventName, TEventArgs eventArgs) where TEventArgs : EventArgs
    {
        var eventDelegate = (MulticastDelegate)source.GetType().GetField(eventName, BindingFlags.Instance | BindingFlags.NonPublic).GetValue(source);
        if (eventDelegate == null)
            return;
        foreach (var handler in eventDelegate.GetInvocationList())
        {
#if !(NETSTANDARD1_6 || NETSTANDARD1_5 || NETSTANDARD1_4 || NETSTANDARD1_3 || NETSTANDARD1_2 || NETSTANDARD1_1 || NETSTANDARD1_0)
            handler.Method?.Invoke(handler.Target, new object[] { source, eventArgs });
#else
            handler.GetMethodInfo()?.Invoke(handler.Target, new object[] { source, eventArgs });
#endif
        }
    }
#endif
}
like image 109
rittergig Avatar answered Mar 21 '23 01:03

rittergig


What I would do is having a viewmodel with a command that performs whatever logic would be done when pressing the button .

Then bind the Command property of the button to the command property in the ViewModel.

At this stage you will have a command that you can execute programmatically just as if you called "Button.Click()" if there will be such thing .

like image 21
Ahmad ElMadi Avatar answered Mar 21 '23 00:03

Ahmad ElMadi