Skip to content

Extension library intended to be used with MAUI. Extra functionality for Views, ViewModels and Services.

License

Notifications You must be signed in to change notification settings

zleao/zoft.MauiExtensions

Repository files navigation

zoft.MauiExtensions

Set of tools designed to be used in MAUI projects, including Views, ViewModels, Services, Extensions and more...

Nuget Package Current Version
zoft.MauiExtensions.Core NuGet

!! Sample App !!

I'm currently in the process of deploying a sample app (Android) to demonstrate the capabilities of the package. If you're interested in becoming a tester to allow the app to be published, please add your email in the issue created for this purpose: Sample App Testing

Getting Started

Install nuget package: zoft.MauiExtensions.Core

Install-Package zoft.MauiExtensions.Core

How To Use

Refer to the sample to have a better understanding of package capabilities. Bellow you can find the most common features and how to use them


Localization Service

The package provides a set of tools to implement localization in your app:

  • ILocalizationService: Interface for the localization service. The interface exists to make it easier to use iwith IOC and to override the base implementation
  • ResourceManagerLocalizationService: Implementation of the ILocalizationService using resource files (.resx)
builder.Services.AddSingleton<ILocalizationService>(new ResourceManagerLocalizationService(AppResources.ResourceManager, SupportedLanguages.DefaultLanguage));
  • TranslationMarkup: XAML markup that provides an easy way to apply the translation directly in XAML
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:zoft="http://zoft.maui.extensions"
             x:Class="zoft.MauiExtensions.Sample.Views.LocalizationView"
             Title="{zoft:Translate LocalizationPage_Title}">
    ...
    ...
    <ScrollView>
        <VerticalStackLayout Spacing="10">
            <Label Text="{zoft:Translate LocalizationPage_Label1}" FontSize="16" FontAttributes="Bold"/>
            <Label Text="{zoft:Translate LocalizationPage_Label2}" />
            <Label Text="{zoft:Translate LocalizationPage_Label3}" FontAttributes="Italic" BackgroundColor="LightGray"/>
        </VerticalStackLayout>
    </ScrollView>
    ...
</ContentPage>


Base Models

Based on the Component Models of the CommunityToolkit.MVVM, the package provides a set of base models that can be used to create Models, ViewModels and Services in your app.

  • ZoftObservableObject: Based on the ObservableObject class, provides a base implementation of the INotifyPropertyChanged interface with additional features:

    • IsBusy and IsNotBusy properties for UI binding
    • BusyMessage property for displaying status messages
    • DoWorkAsync() methods for executing background tasks with busy state management
    • Implements IDisposable for proper resource cleanup
  • ZoftObservableRecipient: Based on the ObservableRecipient class, provides messaging capabilities:

    • Inherits all features from ZoftObservableObject
    • Built-in messenger functionality for communication between ViewModels
    • Automatic message registration and cleanup
    • Broadcast() method for sending property change messages
  • ZoftObservableValidator: Based on the ObservableValidator class, provides validation capabilities:

    • All features of ZoftObservableObject
    • Data annotation validation support
    • ValidateAllProperties() and ClearErrors() methods
    • Override OnErrorsChanged() to handle validation state changes
    • Automatic error collection and management


Busy Notification Management

Base models provide methods to execute code in a background thread, while providing with updated on IsBusy and BusyMessage properties that can be bound to an UI element (i.e. ActivityIndicator)

await DoWorkAsync(() => ..., "Busy Message");

var result = await DoWorkAsync(() => return some_object, "BusyMessage");


Validation

The ZoftObservableValidator base class provides comprehensive validation capabilities using data annotations:

public partial class ValidationViewModel : ZoftObservableValidator
{
    [ObservableProperty]
    [Required]
    [MinLength(2)]
    [MaxLength(100)]
    public partial string FirstName { get; set; }

    [ObservableProperty]
    [Required]
    [EmailAddress]
    public partial string Email { get; set; }

    protected override void OnErrorsChanged(INotifyDataErrorInfo source, ZoftObservableValidator target, DataErrorsChangedEventArgs e)
    {
        base.OnErrorsChanged(source, target, e);

        ErrorMessage = string.Join(Environment.NewLine, GetErrors().Select(e => e.ErrorMessage));
    }

    [RelayCommand]
    private void Validate()
    {
        ValidateAllProperties();
    }

    [RelayCommand]
    private void ClearValidation()
    {
        ClearErrors();
    }
}


Messenger and Communication

The ZoftObservableRecipient base class provides built-in messaging capabilities for ViewModel communication:

public partial class MessengerViewModel : ZoftObservableRecipient, 
    IRecipient<PropertyChangedMessage<string>>, 
    IRecipient<CustomMessage>
{
    public MessengerViewModel() : base()
    {
        IsActive = true; // Enable message reception
    }

    // Receive property change messages
    void IRecipient<PropertyChangedMessage<string>>.Receive(PropertyChangedMessage<string> message)
    {
        if (message.PropertyName == nameof(Text))
            Text = message.NewValue;
    }

    // Receive custom messages
    void IRecipient<CustomMessage>.Receive(CustomMessage message)
    {
        // Handle custom message
    }

    [RelayCommand]
    private void SendMessage()
    {
        // Broadcast property changes
        Broadcast(oldValue, newValue, nameof(PropertyName));
        
        // Send custom messages
        Messenger.Send<CustomMessage>();
    }
}


Weak Subscription

The package provides a set of extension methods to subscribe to events using weak references, avoiding memory leaks when the subscriber is not disposed properly:

more info will come...



Extensions

The library provides numerous extension methods to simplify common operations:

Collection Extensions

// Add missing items to a collection
targetCollection.AddMissing(itemsToAdd);
targetCollection.AddMissing(itemsToAdd, customValidationFunc);

// Safe count with fallback
int count = collection.Count(fallbackValue: 0);

String Extensions

// Null-safe string operations
bool isEmpty = text.IsNullOrEmpty();
bool isWhitespace = text.IsNullOrWhiteSpace();

// Template formatting with null safety
string result = template.FormatTemplate(arg1, arg2);

// Regular expression matching
bool matches = input.IsMatch(@"\d+");
string extract = input.Extract(@"(\d+)");

DateTime Extensions

// Null-safe formatting
string formatted = nullableDate.Format("yyyy-MM-dd");

// Date operations
DateTime dateOnly = dateTime.ToDate();
string shortDate = dateTime.ToShortDateString();
DateTime utcAdjusted = dateTime.GetUtcAdjustedTime();

Object Extensions

// Reflection-based property access
object value = obj.GetPropertyValue("PropertyName");
string stringValue = obj.GetPropertyValueAsString("PropertyName", "default");
obj.SetPropertyValue("PropertyName", newValue);

// Null checking
var nonNull = obj.ThrowIfNull(nameof(obj));

Task Extensions

// Timeout support
var result = await task.WithTimeout(5000); // 5 seconds
var result = await task.WithTimeout(TimeSpan.FromMinutes(1));

// Safe fire-and-forget execution
task.SafeFireAndForget(onException: ex => Console.WriteLine(ex.Message));

List Extensions

// Find index with predicate
int index = list.FindIndex(item => item.Name == "test");

// Apply action to all items
list.ForEach(item => item.Process());

Dictionary Extensions

// Safe operations
dictionary.AddOrUpdate(key, value);
dictionary.AddOrUpdate(keyValuePairs); // Bulk operations
dictionary.AddOrIgnore(keyValuePairs); // Add only if key doesn't exist
dictionary.RemoveIfExists(key);

// Apply action to all items
dictionary.ForEach((key, value) => Console.WriteLine($"{key}: {value}"));

// Convert to tuple list
var tuples = dictionary.ToTupleList();

Exception Extensions

// Get full exception description including inner exceptions
string fullDescription = exception.GetFullDescription();

Type Extensions

// Get properties with various options
var publicProps = type.GetProperties(onlyPublic: true);
var allProps = type.GetProperties(onlyPublic: false, includeInherited: true);

About

Extension library intended to be used with MAUI. Extra functionality for Views, ViewModels and Services.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •