Editing: maui_base1


maui_base1

I'll analyze the code-behind files to document C# patterns, event handlers, and common practices used in this project.

.NET MAUI C# Code-Behind Patterns & Event Handlers Guide

📋 Table of Contents

  1. Page Structure & Lifecycle
  2. Common Event Handlers
  3. Database Operations
  4. Navigation Patterns
  5. Validation Patterns
  6. API Integration
  7. UI State Management
  8. Common Utilities

1. Page Structure & Lifecycle

Basic Page Class Structure

using CERS.Models;
using CERS.WebApi;
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Controls.Xaml;

namespace CERS
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class YourPage : ContentPage
    {
        // Database instances
        UserDetailsDatabase userDetailsDatabase = new UserDetailsDatabase();
        ExpenditureDetailsDatabase expenditureDetailsDatabase = new ExpenditureDetailsDatabase();

        // Data lists
        List<UserDetails> userDetails = new();
        List<ExpenditureDetails> expenditureDetailslist = new();

        // Variables
        string selectedDate = string.Empty;

        public YourPage()
        {
            InitializeComponent();
            // Initialize UI elements here
        }

        protected override void OnAppearing()
        {
            base.OnAppearing();
            // Load data when page appears
            LoadData();
        }
    }
}

Key Lifecycle Methods


2. Common Event Handlers

Button Click Events

// Async button click (for API calls, navigation)
private async void btn_save_Clicked(object sender, EventArgs e)
{
    if (await checkvalidation())
    {
        Loading_activity.IsVisible = true;
        var service = new HitServices();
        int response = await service.SaveData(data);
        Loading_activity.IsVisible = false;

        if (response == 200)
        {
            await DisplayAlert("Success", "Data saved", "OK");
            Application.Current!.MainPage = new NavigationPage(new DashboardPage());
        }
    }
}

// Sync button click (for simple UI changes)
private void btn_cancel_Clicked(object sender, EventArgs e)
{
    Navigation.PopAsync();
}

Entry/Editor Text Changed

private void entry_mobileno_TextChanged(object sender, TextChangedEventArgs e)
{
    string oldText = e.OldTextValue;
    string newText = e.NewTextValue;

    // Validate or format input
    if (newText.Length > 10)
    {
        entry_mobileno.Text = oldText;
    }
}

DatePicker Date Selected

private void datepicker_expdate_DateSelected(object sender, DateChangedEventArgs e)
{
    DateTime selectedDate = e.NewDate;
    expendituredateselected = selectedDate.ToString("yyyy/MM/dd");

    // Update UI
    lbl_selecteddate.Text = selectedDate.ToString("dd/MM/yyyy");
}

Picker Selection Changed

private void picker_payMode_SelectedIndexChanged(object sender, EventArgs e)
{
    if (picker_payMode.SelectedIndex != -1)
    {
        var selectedItem = paymentModeslist.ElementAt(picker_payMode.SelectedIndex);
        paymodecode = selectedItem.paymode_code;

        // Conditional UI updates based on selection
        if (paymodecode.Equals("1"))
        {
            lbl_voucherBillNumber.Text = "Bill Number*";
        }
        else if (paymodecode.Equals("2"))
        {
            lbl_voucherBillNumber.Text = "Cheque Number*";
        }
    }
}

RadioButton Checked Changed

private void rb_exp_CheckedChanged(object sender, CheckedChangedEventArgs e)
{
    if (rb_exptype.IsChecked)
    {
        loadexptypewisedata();
    }
    else if (rb_expdate.IsChecked)
    {
        loadexpdatewisedata();
    }
}

ListView Item Tapped

private void listView_expendituredetails_ItemTapped(object sender, ItemTappedEventArgs e)
{
    var currentRecord = e.Item as ExpenditureDetails;

    if (currentRecord != null)
    {
        string expCode = currentRecord.expCode;
        Navigation.PushAsync(new ViewDetailsPage(expCode));
    }
}

TapGestureRecognizer Tapped

private async void Tab_Home_Tapped(object sender, EventArgs e)
{
    Preferences.Set("Active", 0);
    Application.Current!.MainPage = new NavigationPage(new DashboardPage());
}

SearchBar Text Changed

private void searchbar_expendituredetails_TextChanged(object sender, TextChangedEventArgs e)
{
    if (!string.IsNullOrEmpty(searchbar.Text))
    {
        string searchText = searchbar.Text.ToLower().Trim();
        listView.ItemsSource = expenditureDetailslist
            .Where(x => x.ExpTypeName.ToLower().Contains(searchText))
            .ToList();
    }
    else
    {
        listView.ItemsSource = expenditureDetailslist;
    }
}

Entry/Editor Focused (Custom Popup Picker)

private void editor_exptype_Focused(object sender, FocusEventArgs e)
{
    editor_exptype.Unfocus(); // Prevent keyboard
    popupexptype.IsVisible = true; // Show custom picker
    listview_exptype.ItemsSource = expenseSourceslist;
}

ViewCell Appearing (Alternate Row Colors)

private bool isRowEven;

private void ViewCell_Appearing(object sender, EventArgs e)
{
    var viewCell = (ViewCell)sender;
    if (viewCell.View != null)
    {
        if (isRowEven)
        {
            viewCell.View.BackgroundColor = Color.FromArgb("#FFFFFF");
        }
        else
        {
            viewCell.View.BackgroundColor = Color.FromArgb("#FCF2F0");
        }
    }
    isRowEven = !isRowEven;
}

3. Database Operations

Query Data

// Simple query
userDetails = userDetailsDatabase.GetUserDetails("Select * from UserDetails").ToList();

// Query with WHERE clause
string query = "Select * from ExpenditureDetails where ExpStatus='P'";
expenditureDetailslist = expenditureDetailsDatabase.GetExpenditureDetails(query).ToList();

// Query with GROUP BY and aggregation
string query = $"Select *, sum(amount) as Totalamount " +
               $"from ExpenditureDetails " +
               $"group by expCode";
expenditureDetailslist = expenditureDetailsDatabase.GetExpenditureDetails(query).ToList();

Check if Data Exists

if (expenditureDetailslist.Any())
{
    // Data exists
    string totalAmount = expenditureDetailslist.ElementAt(0).Totalamount;
}
else
{
    // No data
    lbl_norecords.IsVisible = true;
}

Update Data

userDetailsDatabase.UpdateCustomquery("update userDetails set IsLoggedIn='Y'");

Delete Data

userDetailsDatabase.DeleteUserDetails();

4. Navigation Patterns

Navigate to New Page

// Push to navigation stack (with back button)
await Navigation.PushAsync(new ViewExpenditureDetailsPage(param1, param2));

// Replace entire navigation stack
Application.Current!.MainPage = new NavigationPage(new DashboardPage());

Navigate with Parameters

// In source page
Navigation.PushAsync(new ViewExpenditureDetailsPage(expendselected, expCode, expDate));

// In target page constructor
public ViewExpenditureDetailsPage(string type, string code, string date)
{
    InitializeComponent();
    this.selectedType = type;
    this.selectedCode = code;
}

Navigate Back

await Navigation.PopAsync();

5. Validation Patterns

Validation Method Pattern

private async Task<bool> checkvalidation()
{
    try
    {
        if (string.IsNullOrEmpty(entry_mobileno.Text))
        {
            await DisplayAlert("CERS", "Enter Mobile No.", "Close");
            return false;
        }

        if (entry_mobileno.Text.Length < 10)
        {
            await DisplayAlert("CERS", "Enter 10 digit Mobile No.", "Close");
            return false;
        }

        if (!App.isNumeric(entry_mobileno.Text))
        {
            await DisplayAlert("CERS", "Only numeric characters allowed", "Close");
            return false;
        }

        if (picker_payMode.SelectedIndex == -1)
        {
            await DisplayAlert("CERS", "Select Payment Mode", "Close");
            return false;
        }
    }
    catch (Exception ex)
    {
        await DisplayAlert("Error", ex.Message, "Close");
        return false;
    }
    return true;
}

Usage in Button Click

private async void btn_save_Clicked(object sender, EventArgs e)
{
    if (await checkvalidation())
    {
        // Proceed with save
    }
}

6. API Integration

API Call Pattern

private async void btn_getotp_Clicked(object sender, EventArgs e)
{
    if (await checkvalidation())
    {
        Loading_activity.IsVisible = true;

        var service = new HitServices();
        int response = await service.GetOtp(entry_mobileno.Text.Trim());

        Loading_activity.IsVisible = false;

        if (response == 200)
        {
            // Success
            await DisplayAlert("Success", "OTP sent", "OK");
            stack_submitotp.IsVisible = true;
        }
        else
        {
            // Failure
            await DisplayAlert("Error", "Failed to send OTP", "OK");
        }
    }
}

Multiple Sequential API Calls

private async void refreshdata()
{
    Loading_activity.IsVisible = true;

    var service = new HitServices();
    await service.ExpenseSources_Get();
    await service.PaymentMode_Get();
    await service.ExpenditureDetails_Get();
    await service.userlogin_Get(usermobileno.Trim());

    Loading_activity.IsVisible = false;
    Application.Current!.MainPage = new NavigationPage(new DashboardPage());
}

Check Internet Connection

var current = Connectivity.NetworkAccess;
if (current == NetworkAccess.Internet)
{
    // Make API call
    int response = await service.SaveData();
}
else
{
    await DisplayAlert("Error", "No Internet Connection", "OK");
}

7. UI State Management

Show/Hide Loading Indicator

Loading_activity.IsVisible = true;
// Do work
Loading_activity.IsVisible = false;

Show/Hide Popup

// Show
popupDetails_Verified.IsVisible = true;

// Hide
popupDetails_Verified.IsVisible = false;

Enable/Disable Controls

entry_mobileno.IsReadOnly = true;
btn_getotp.IsEnabled = false;
btn_save.IsVisible = false;

Update Control Properties

lbl_heading.Text = "Dashboard";
lbl_heading.TextColor = Colors.Navy;
btn_save.BackgroundColor = Colors.Green;
entry_amount.Text = "0";

Bind Data to ListView/CollectionView

listView_expendituredetails.ItemsSource = expenditureDetailslist;

// Clear binding
listView_expendituredetails.ItemsSource = null;

Bind Data to Picker

picker_payMode.ItemsSource = paymentModeslist;

// Set display property
if (App.Language == 0)
{
    picker_payMode.ItemDisplayBinding = new Binding("paymode_Desc");
}
else
{
    picker_payMode.ItemDisplayBinding = new Binding("paymode_Desc_Local");
}

// Set selected item
picker_payMode.SelectedIndex = 0;

Update Footer Tab Icons (Active State)

// Arrays for footer management
public Label[] Footer_Labels = new Label[3];
public Image[] Footer_Images = new Image[3];
public string[] Footer_Image_Source = new string[3];

// Initialize in constructor
Footer_Labels = new Label[3] { Tab_Home_Label, Tab_New_Label, Tab_Settings_Label };
Footer_Images = new Image[3] { Tab_Home_Image, Tab_New_Image, Tab_Settings_Image };
Footer_Image_Source = new string[3] { "ic_home.png", "ic_addwhite.png", "ic_morewhite.png" };

// Update active tab
Footer_Images[Preferences.Get("Active", 0)].Source = Footer_Image_Source[Preferences.Get("Active", 0)];
Footer_Labels[Preferences.Get("Active", 0)].TextColor = Color.FromArgb("#0f0f0f");

8. Common Utilities

Preferences (Persistent Storage)

// Save
Preferences.Set("Active", 0);
Preferences.Set("UserType", "Candidate");
Preferences.Set("USEROTPVERIFIED", "Y");

// Retrieve
int activeTab = Preferences.Get("Active", 0); // 0 is default
string userType = Preferences.Get("UserType", "");

DisplayAlert (Dialogs)

// Simple alert
await DisplayAlert("Title", "Message", "OK");

// Confirmation dialog
bool result = await DisplayAlert("Confirm", "Are you sure?", "Yes", "No");
if (result)
{
    // User clicked Yes
}

Date Formatting

DateTime date = DateTime.Now;
string formatted = date.ToString("dd/MM/yyyy");
string dbFormat = date.ToString("yyyy/MM/dd");

// Parse date
DateTime parsed = DateTime.Parse("2024-01-15");
DateTime converted = Convert.ToDateTime(userDetails.ElementAt(0).NominationDate);

String Operations

// Check empty
if (string.IsNullOrEmpty(entry_mobileno.Text))

// Trim whitespace
string clean = entry_mobileno.Text.Trim();

// Convert to lowercase
string lower = searchText.ToLower();

// Replace characters
string formatted = date.ToString("yyyy/MM/dd").Replace('-', '/');

LINQ Operations

// Filter
var filtered = expenditureDetailslist
    .Where(x => x.ExpStatus == "P")
    .ToList();

// Search
var searched = expenditureDetailslist
    .Where(x => x.ExpTypeName.ToLower().Contains(searchText))
    .ToList();

// Get first element
var first = expenditureDetailslist.ElementAt(0);

// Check if any
if (expenditureDetailslist.Any())
{
    // Has data
}

// Count
int count = expenditureDetailslist.Count;

File Picker (PDF Upload)

private async void btn_uploaddoc_Clicked(object sender, EventArgs e)
{
    await PickAndShow(PickOptions.Default, 1);
}

async Task<FileResult?> PickAndShow(PickOptions options, int docnumber)
{
    try
    {
        var result = await FilePicker.PickAsync(options);
        if (result != null)
        {
            if (result.FileName.EndsWith("pdf", StringComparison.OrdinalIgnoreCase))
            {
                var stream = await result.OpenReadAsync();
                long length = stream.Length / 1024; // KB

                if (length >= 1024) // 1MB limit
                {
                    await DisplayAlert("Error", "File size exceeds 1MB", "OK");
                }
                else
                {
                    string base64 = App.ConvertToBase64(stream);
                    btn_uploadpdf.BackgroundColor = Colors.Green;
                    btn_uploadpdf.Text = "Uploaded";
                }
            }
            else
            {
                await DisplayAlert("Error", "Only PDF files allowed", "OK");
            }
        }
        return result;
    }
    catch (Exception ex)
    {
        Console.WriteLine("Exception: " + ex.ToString());
    }
    return null;
}

Launch External URL

private void btn_form46_Clicked(object sender, EventArgs e)
{
    var service = new HitServices();
    string url = service.baseurl + $"GetDeclarationPdf.aspx?MobileNo={usermobileno}";
    Launcher.OpenAsync(url);
}

9. App.xaml.cs Patterns

Global Static Methods

// Get localized label
string label = App.GetLabelByKey("AppName");

// Validation helpers
bool isValid = App.isNumeric(entry_mobileno.Text);
bool isAlpha = App.isAlphabetonly(entry_name.Text);
bool isAlphaNum = App.isAlphaNumeric(entry_address.Text);

// Convert stream to Base64
string base64 = App.ConvertToBase64(stream);

// Get user heading
string heading = App.setselfagentuserheading();

Global Variables

// Access global language setting
int language = App.Language;

// Access app name
string appName = App.AppName;

// Access button text
string closeBtn = App.Btn_Close;

10. Common Patterns Summary

Pattern 1: Load Data on Page Appear

protected override void OnAppearing()
{
    base.OnAppearing();
    userDetails = userDetailsDatabase.GetUserDetails("Select * from UserDetails").ToList();

    if (userDetails.Any())
    {
        lbl_heading.Text = userDetails.ElementAt(0).VOTER_NAME;
    }
}

Pattern 2: Conditional UI Updates

if (expenditureDetailslist.Any())
{
    listView.ItemsSource = expenditureDetailslist;
    lbl_norecords.IsVisible = false;
    btn_submit.IsVisible = true;
}
else
{
    listView.ItemsSource = null;
    lbl_norecords.IsVisible = true;
    btn_submit.IsVisible = false;
}

Pattern 3: Try-Catch for Safe Operations

try
{
    DateTime date = DateTime.Parse(userDetails.ElementAt(0).ResultDate);
    datepicker.MaximumDate = date;
}
catch
{
    // Use default or fallback
    datepicker.MaximumDate = DateTime.Now;
}

Pattern 4: Null-Safe Access

var currentRecord = e.Item as ExpenditureDetails;
string expCode = currentRecord?.expCode ?? "";

Pattern 5: MainThread Operations (UI Updates)

MainThread.BeginInvokeOnMainThread(() =>
{
    lbl_status.Text = "Updated";
    Loading_activity.IsVisible = false;
});

11. How to Edit/Remove Code

To Remove a Field:

  1. Delete XAML control (Label + Entry)
  2. Remove variable declaration
  3. Remove validation in checkvalidation() method
  4. Remove from API call parameters
  5. Remove event handlers if any

To Add a New Field:

  1. Add XAML (Label + Entry)
  2. Declare variable if needed
  3. Add validation in checkvalidation()
  4. Add to API call parameters
  5. Initialize in OnAppearing() if needed

To Modify Event Handler:

  1. Find method by name (e.g., btnsaveClicked)
  2. Modify logic inside method
  3. Test thoroughly

12. Debugging Tips

Console Output

Console.WriteLine("Debug: " + variableName);
System.Diagnostics.Debug.WriteLine($"Value: {value}");

Display Values in Alert

await DisplayAlert("Debug", $"Value: {entry_amount.Text}", "OK");

Check for Null

if (userDetails == null || userDetails.Count == 0)
{
    await DisplayAlert("Error", "No user data", "OK");
    return;
}

This guide covers all major C# patterns used in your MAUI project. Use it as a reference when editing or creating new functionality.