### Dependency Injection Usage Example Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/api-reference/IMessagingCenter.md Demonstrates injecting IMessagingCenter into a DataService for sending messages and into a DetailPage for subscribing to messages. ```csharp public class DataService { private readonly IMessagingCenter _messagingCenter; public DataService(IMessagingCenter messagingCenter) { _messagingCenter = messagingCenter; } public void LoadData() { // Send a message that data has loaded _messagingCenter.Send(this, "DataLoaded", "Success"); } } public partial class DetailPage : ContentPage { private readonly IMessagingCenter _messagingCenter; public DetailPage(IMessagingCenter messagingCenter) { InitializeComponent(); _messagingCenter = messagingCenter; _messagingCenter.Subscribe(this, "DataLoaded", (sender, message) => { DisplayAlert("Info", message, "OK"); }); } } ``` -------------------------------- ### Complete MessagingCenter Usage Example Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/api-reference/MessagingCenter.md Demonstrates subscribing to and unsubscribing from messages with and without arguments, and sending messages. Always unsubscribe to prevent memory leaks. Type parameters must match exactly between Send and Subscribe calls. ```csharp using Plugin.Maui.MessagingCenter; public partial class MainPage : ContentPage { public MainPage() { InitializeComponent(); } protected override void OnAppearing() { base.OnAppearing(); // Subscribe to messages with arguments MessagingCenter.Subscribe(this, "UserSelected", (sender, userName) => { StatusLabel.Text = $"Selected: {userName}"; }); // Subscribe to messages without arguments MessagingCenter.Subscribe(this, "DataRefreshed", (sender) => { LoadData(); }); } protected override void OnDisappearing() { base.OnDisappearing(); // Always unsubscribe to prevent memory leaks MessagingCenter.Unsubscribe(this, "UserSelected"); MessagingCenter.Unsubscribe(this, "DataRefreshed"); base.OnDisappearing(); } } public partial class DetailPage : ContentPage { private void OnUserSelected(string userName) { // Send message with argument MessagingCenter.Send(this, "UserSelected", userName); // Send message without argument MessagingCenter.Send(this, "DataRefreshed"); } } ``` -------------------------------- ### MessagingCenter Static Class Reference Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/MANIFEST.txt Reference for the static MessagingCenter class, including its Instance property and all 6 public methods. Documentation covers type parameters, arguments, return types, exceptions, and usage examples. ```APIDOC ## MessagingCenter Static Class ### Description Provides static access to messaging functionalities, allowing for cross-thread and cross-component communication within a .NET MAUI application. ### Methods #### Instance Property - **Instance** (IMessagingCenter) - Gets the singleton instance of the MessagingCenter. #### Send() ### Description Sends a message with arguments to all subscribers. ### Method `Send()` ### Parameters - **TSender** (Type) - The type of the sender. - **TArgs** (Type) - The type of the message arguments. - **messageKey** (string) - The unique key identifying the message. - **sender** (TSender) - The instance of the sender. - **args** (TArgs) - The arguments for the message. #### Send() ### Description Sends a message without arguments to all subscribers. ### Method `Send()` ### Parameters - **TSender** (Type) - The type of the sender. - **messageKey** (string) - The unique key identifying the message. - **sender** (TSender) - The instance of the sender. #### Subscribe() ### Description Subscribes a callback to receive messages with arguments. ### Method `Subscribe()` ### Parameters - **TSender** (Type) - The type of the sender. - **TArgs** (Type) - The type of the message arguments. - **messageKey** (string) - The unique key identifying the message. - **sender** (TSender) - The sender instance to filter messages from. - **callback** (Action) - The action to execute when the message is received. #### Subscribe() ### Description Subscribes a callback to receive messages without arguments. ### Method `Subscribe()` ### Parameters - **TSender** (Type) - The type of the sender. - **messageKey** (string) - The unique key identifying the message. - **sender** (TSender) - The sender instance to filter messages from. - **callback** (Action) - The action to execute when the message is received. #### Unsubscribe() ### Description Unsubscribes a specific callback for messages with arguments. ### Method `Unsubscribe()` ### Parameters - **TSender** (Type) - The type of the sender. - **TArgs** (Type) - The type of the message arguments. - **messageKey** (string) - The unique key identifying the message. - **sender** (TSender) - The sender instance to filter messages from. #### Unsubscribe() ### Description Unsubscribes a specific callback for messages without arguments. ### Method `Unsubscribe()` ### Parameters - **TSender** (Type) - The type of the sender. - **messageKey** (string) - The unique key identifying the message. - **sender** (TSender) - The sender instance to filter messages from. ### Error Handling - **ArgumentNullException**: Thrown if a required parameter is null. - **InvalidOperationException**: Thrown for duplicate subscriptions. ``` -------------------------------- ### Use Constants for Message Keys Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/errors.md Define message keys as constants to prevent typos and facilitate easier refactoring. This example shows defining constants and then using them for subscription. ```csharp public static class MessageKeys { public const string LocationUpdated = "LocationUpdated"; public const string DataRefreshed = "DataRefreshed"; } // Use constants to prevent mistakes MessagingCenter.Subscribe(this, MessageKeys.LocationUpdated, handler); ``` -------------------------------- ### Catching InvalidOperationException Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/errors.md This example shows how to use a try-catch block to gracefully handle the InvalidOperationException that occurs when a duplicate subscription is attempted. ```csharp try { MessagingCenter.Subscribe(this, "LocationUpdate", (sender, location) => { }); MessagingCenter.Subscribe(this, "LocationUpdate", (sender, location) => { }); } catch (InvalidOperationException ex) { Console.WriteLine($"Duplicate subscription: {ex.Message}"); // The message will contain something like: // "The target recipient has already subscribed to the target message." ``` -------------------------------- ### Define Message Key Constants Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/COMMON_PATTERNS.md Use constants for message keys to prevent typos and enable easy refactoring. This example shows how to define constants for various message types. ```csharp public static class MessageKeys { // Navigation messages public const string NavigateToDetail = "NavigateToDetail"; public const string NavigateBack = "NavigateBack"; // Data messages public const string DataLoaded = "DataLoaded"; public const string DataError = "DataError"; public const string ItemSelected = "ItemSelected"; // UI messages public const string ThemeChanged = "ThemeChanged"; public const string LanguageChanged = "LanguageChanged"; // Authentication messages public const string LoginSuccess = "LoginSuccess"; public const string LoginFailed = "LoginFailed"; public const string Logout = "Logout"; } // Usage public class MainViewModel { public void SelectItem(Item item) { MessagingCenter.Send( this, MessageKeys.ItemSelected, item); } } public partial class ListPage : ContentPage { protected override void OnAppearing() { base.OnAppearing(); MessagingCenter.Subscribe( this, MessageKeys.ItemSelected, (sender, item) => NavigateToDetail(item)); } } ``` -------------------------------- ### Service-to-UI Communication: Subscribing to Service Events Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/COMMON_PATTERNS.md Subscribe to messages from a background service in the UI to update elements like maps. Ensure to start the service and unsubscribe when the page is disposed. ```csharp public partial class MapPage : ContentPage { private LocationService _locationService; private Map _map; public MapPage() { InitializeComponent(); _locationService = new LocationService(); } protected override async void OnAppearing() { base.OnAppearing(); MessagingCenter.Subscribe( this, "LocationUpdated", (sender, location) => { UpdateMapPin(location); }); await _locationService.StartTrackingAsync(); } protected override void OnDisappearing() { base.OnDisappearing(); MessagingCenter.Unsubscribe(this, "LocationUpdated"); } } ``` -------------------------------- ### Send and Subscribe with Arguments Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/README.md Demonstrates sending a message with string arguments and subscribing to it. Type parameters must match exactly between Send and Subscribe. ```csharp MessagingCenter.Send(this, "LocationUpdate", "New York"); MessagingCenter.Subscribe(this, "LocationUpdate", (sender, location) => { }); ``` -------------------------------- ### Get Default MessagingCenter Instance Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/api-reference/MessagingCenter.md Retrieves the singleton instance of IMessagingCenter, which is used by all static methods for message publishing and subscribing. ```csharp public static IMessagingCenter Instance { get; } ``` -------------------------------- ### Send and Subscribe with Arguments Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/README.md Demonstrates sending a message with string data and subscribing to receive it. Handles the received data by displaying an alert. ```csharp // Send a message with data MessagingCenter.Send(this, "LocationUpdate", "New York"); // In another class, subscribe to receive the message MessagingCenter.Subscribe(this, "LocationUpdate", (sender, location) => { // Handle the location update DisplayAlert("Location", $ ``` ```csharp New location: {location}", "OK"); }); ``` -------------------------------- ### Include Raw Assets in .NET MAUI Project Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/samples/Plugin.Maui.MessagingCenter.Sample/Resources/Raw/AboutAssets.txt Add this entry to your .csproj file to include all files in the Resources\Raw directory and its subdirectories as deployable assets. ```xml ``` -------------------------------- ### Basic Publish-Subscribe Pattern in MAUI Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/OVERVIEW.md Demonstrates a basic publish-subscribe pattern where a MainPage subscribes to messages from a DetailPage, and the DetailPage publishes messages. ```csharp public partial class MainPage : ContentPage { protected override void OnAppearing() { base.OnAppearing(); // Subscribe to messages MessagingCenter.Subscribe(this, "ItemSelected", (sender, selectedItem) => { DisplayAlert("Selected", selectedItem, "OK"); }); } protected override void OnDisappearing() { base.OnDisappearing(); // Always unsubscribe MessagingCenter.Unsubscribe(this, "ItemSelected"); } } public partial class DetailPage : ContentPage { private void OnItemTapped(string item) { // Publish message MessagingCenter.Send(this, "ItemSelected", item); } } ``` -------------------------------- ### Load Raw Asset at Runtime Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/samples/Plugin.Maui.MessagingCenter.Sample/Resources/Raw/AboutAssets.txt This C# code demonstrates how to load and read the contents of a raw asset file that has been deployed with your application package using Essentials. ```csharp async Task LoadMauiAsset() { using var stream = await FileSystem.OpenAppPackageFileAsync("AboutAssets.txt"); using var reader = new StreamReader(stream); var contents = reader.ReadToEnd(); } ``` -------------------------------- ### Multiple Subscriptions (.NET MAUI Behavior) Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/BEHAVIOR_DIFFERENCES.md Demonstrates how .NET MAUI's MessagingCenter allows multiple subscriptions to the same message by the same subscriber, invoking all registered callbacks. ```csharp var subscriber = new object(); MessagingCenter.Subscribe(subscriber, "test", (sender, args) => Console.WriteLine("Handler 1")); MessagingCenter.Subscribe(subscriber, "test", (sender, args) => Console.WriteLine("Handler 2")); MessagingCenter.Send(this, "test", "message"); // Both handlers would be called ``` -------------------------------- ### Send and Subscribe without Arguments Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/README.md Shows how to send a simple notification message and subscribe to it for triggering actions like data refresh. ```csharp // Send a simple notification message MessagingCenter.Send(this, "RefreshData"); // Subscribe to the notification MessagingCenter.Subscribe(this, "RefreshData", (sender) => { // Refresh your data LoadData(); }); ``` -------------------------------- ### Alternative Safe Subscription by Unsubscribing First Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/COMMON_PATTERNS.md Simplify subscription management by always unsubscribing before subscribing. This pattern is safe because unsubscribing from a non-existent subscription is a no-operation. ```csharp public partial class SimplePage : ContentPage { protected override void OnAppearing() { base.OnAppearing(); // Safe even if not subscribed (unsubscribe of non-existent subscription is a no-op) MessagingCenter.Unsubscribe(this, "StatusChanged"); MessagingCenter.Subscribe( this, "StatusChanged", (sender, status) => { StatusLabel.Text = status; }); } protected override void OnDisappearing() { base.OnDisappearing(); MessagingCenter.Unsubscribe(this, "StatusChanged"); } } ``` -------------------------------- ### Dependency Injection with IMessagingCenter Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/OVERVIEW.md Shows how to use dependency injection with the IMessagingCenter interface to send and receive messages within different services and pages. ```csharp public class DataService { private readonly IMessagingCenter _messagingCenter; public DataService(IMessagingCenter messagingCenter) { _messagingCenter = messagingCenter; } public async Task LoadDataAsync() { var data = await FetchDataAsync(); _messagingCenter.Send>("DataLoaded", data); } } public partial class ListPage : ContentPage { private readonly DataService _service; public ListPage(DataService service) { InitializeComponent(); _service = service; _messagingCenter.Subscribe>(this, "DataLoaded", (sender, items) => DisplayItems(items)); } } ``` -------------------------------- ### Subscribe-Unsubscribe-Subscribe Lifecycle Support Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/OVERVIEW.md Illustrates the supported lifecycle of subscribing, unsubscribing, and re-subscribing to messages in Plugin.Maui.MessagingCenter. ```csharp // Subscribe Subscribe(subscriber, "test", handler); Send(sender, "test"); // Delivered // Unsubscribe Unsubscribe(subscriber, "test"); Send(sender, "test"); // NOT delivered // Subscribe again Subscribe(subscriber, "test", handler); Send(sender, "test"); // Delivered again ``` -------------------------------- ### Inject IMessagingCenter for Testability Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/COMMON_PATTERNS.md Demonstrates how to inject IMessagingCenter into services and views for easier testing and decoupling. Configure DI to provide the singleton instance of MessagingCenter. ```csharp public class DataService { private readonly IMessagingCenter _messagingCenter; private readonly HttpClient _httpClient; public DataService(IMessagingCenter messagingCenter, HttpClient httpClient) { _messagingCenter = messagingCenter; _httpClient = httpClient; } public async Task LoadDataAsync() { try { var data = await FetchAsync(); _messagingCenter.Send>(this, "DataLoaded", data); } catch (Exception ex) { _messagingCenter.Send(this, "ErrorOccurred", ex.Message); } } } public partial class ListView : ContentPage { private readonly DataService _service; private readonly IMessagingCenter _messagingCenter; public ListView(DataService service, IMessagingCenter messagingCenter) { InitializeComponent(); _service = service; _messagingCenter = messagingCenter; } protected override async void OnAppearing() { base.OnAppearing(); _messagingCenter.Subscribe>( this, "DataLoaded", (sender, items) => DisplayItems(items)); _messagingCenter.Subscribe( this, "ErrorOccurred", (sender, errorMessage) => DisplayError(errorMessage)); await _service.LoadDataAsync(); } protected override void OnDisappearing() { base.OnDisappearing(); _messagingCenter.Unsubscribe>(this, "DataLoaded"); _messagingCenter.Unsubscribe(this, "ErrorOccurred"); } } public static class ServiceCollectionExtensions { public static IServiceCollection AddAppServices(this IServiceCollection services) { services.AddSingleton(MessagingCenter.Instance); services.AddSingleton(); services.AddTransient(); return services; } } ``` -------------------------------- ### Unsubscribe Before Re-subscribing Pattern Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/OVERVIEW.md Shows the recommended pattern for handling re-subscriptions in Plugin.Maui.MessagingCenter by unsubscribing from the previous subscription first. ```csharp Unsubscribe(subscriber, "test"); Subscribe(subscriber, "test", handler2); ``` -------------------------------- ### Using Different Message Keys Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/errors.md This pattern illustrates how to avoid duplicate subscription errors by using distinct message keys for different scenarios or handlers, rather than re-using the same key. ```csharp // Instead of re-subscribing to the same message key: MessagingCenter.Subscribe(subscriber, "DataChanged", handler1); MessagingCenter.Subscribe(subscriber, "DataChanged", handler2); // Error! // Use different message keys: MessagingCenter.Subscribe(subscriber, "DataChangedInitial", handler1); MessagingCenter.Subscribe(subscriber, "DataChangedSecond", handler2); // OK ``` -------------------------------- ### Safe Subscription with OnAppearing and OnDisappearing Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/COMMON_PATTERNS.md Implement safe subscription logic for pages that might be navigated to multiple times. Ensure subscriptions are made only once and unsubscribed when the page disappears to prevent memory leaks. ```csharp public partial class SafePage : ContentPage { private bool _isSubscribed = false; public SafePage() { InitializeComponent(); } protected override void OnAppearing() { base.OnAppearing(); // Safe to call OnAppearing multiple times if (!_isSubscribed) { SubscribeToMessages(); _isSubscribed = true; } } private void SubscribeToMessages() { MessagingCenter.Subscribe( this, "StatusChanged", (sender, status) => { StatusLabel.Text = status; }); } protected override void OnDisappearing() { base.OnDisappearing(); if (_isSubscribed) { MessagingCenter.Unsubscribe(this, "StatusChanged"); _isSubscribed = false; } } } ``` -------------------------------- ### MessagingCenter Static Facade Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/ARCHITECTURE.md Provides a static entry point for messaging operations, maintaining API compatibility with .NET MAUI's MessagingCenter. It delegates calls to the singleton IMessagingCenter instance. ```csharp public static class MessagingCenter { private static readonly IMessagingCenter _instance = new MessagingCenterImpl(); public static IMessagingCenter Instance => _instance; public static void Send(TSender sender, string message, TArgs args) where TSender : class { _instance.Send(sender, message, args); } // ... other delegating methods ... } ``` -------------------------------- ### Using Multiple Subscribers for Same Message Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/BEHAVIOR_DIFFERENCES.md Demonstrates how to use different subscribers for the same message type to handle distinct logic, avoiding duplicate subscriptions on a single subscriber. ```csharp MessagingCenter.Subscribe(subscriber1, "test", FirstHandler); MessagingCenter.Subscribe(subscriber2, "test", SecondHandler); ``` -------------------------------- ### Provide Type Parameters for Subscriptions Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/COMMON_PATTERNS.md Always provide the correct type parameters when subscribing to messages. Omitting them will result in a compilation error due to incomplete type information. ```csharp // BAD: Compilation error - incomplete type information MessagingCenter.Subscribe(this, "Message", handler); ``` ```csharp // GOOD: Complete type information MessagingCenter.Subscribe(this, "Message", handler); ``` -------------------------------- ### Weak vs. Strong Reference Subscribers Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/OVERVIEW.md Demonstrates how the library manages subscriber memory. Weak references allow garbage collection for subscribers without closure capturing, while strong references are maintained for closures that capture the subscriber to ensure message delivery. ```csharp // This allows GC (no closure capturing subscriber) Subscribe(subscriber, "msg", sender => Console.WriteLine("Received")); // This prevents GC (closure captures subscriber, so strong reference is kept) Subscribe(subscriber, "msg", sender => subscriber.Update()); ``` -------------------------------- ### Subscribe-Unsubscribe-Subscribe Pattern Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/BEHAVIOR_DIFFERENCES.md Shows the correct implementation of the subscribe-unsubscribe-subscribe pattern, which is supported by both .NET MAUI MessagingCenter and this plugin. ```csharp var subscriber = new object(); // Subscribe MessagingCenter.Subscribe(subscriber, "test", sender => Console.WriteLine("Received")); // Send (message received) MessagingCenter.Send(this, "test"); // Unsubscribe MessagingCenter.Unsubscribe(subscriber, "test"); // Send (message not received) MessagingCenter.Send(this, "test"); // Subscribe again MessagingCenter.Subscribe(subscriber, "test", sender => Console.WriteLine("Received again")); // Send (message received) MessagingCenter.Send(this, "test"); ``` -------------------------------- ### Consolidating Multiple Actions in One Subscription Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/BEHAVIOR_DIFFERENCES.md Provides an alternative to multiple subscriptions by combining several actions within a single subscription callback. ```csharp MessagingCenter.Subscribe(subscriber, "test", (sender, args) => { HandleFirst(args); HandleSecond(args); }); ``` -------------------------------- ### Update using statements for MessagingCenter Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/OVERVIEW.md Update your using statements to reference the Plugin.Maui.MessagingCenter instead of the original Microsoft.Maui.Controls. ```csharp // From: using Microsoft.Maui.Controls; using Plugin.Maui.MessagingCenter; ``` -------------------------------- ### Simple Event Notifications Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/COMMON_PATTERNS.md Subscribe to app-wide events like language or theme changes without transferring data. Ensure to call Subscribe in the appropriate lifecycle method and Send when the event occurs. ```csharp public class AppShell : Shell { public AppShell() { InitializeComponent(); Subscribe(); } private void Subscribe() { // Listen for app-wide events MessagingCenter.Subscribe(this, "LanguageChanged", sender => OnLanguageChanged()); MessagingCenter.Subscribe(this, "ThemeChanged", sender => OnThemeChanged()); } private void OnLanguageChanged() { // Update all text in the shell ReloadTranslations(); } private void OnThemeChanged() { // Update theme across the app ApplyTheme(); } } public partial class App : Application { public void ChangeLanguage(string language) { SetLanguage(language); // Notify all listeners MessagingCenter.Send(this, "LanguageChanged"); } public void ChangeTheme(AppTheme theme) { SetTheme(theme); // Notify all listeners MessagingCenter.Send(this, "ThemeChanged"); } } ``` -------------------------------- ### Subscribe to a Message with Arguments Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/README.md Static method to subscribe to a message with specific sender and argument types. Requires a callback action. ```csharp public static void Subscribe(object subscriber, string message, Action callback, TSender source = null) where TSender : class ``` -------------------------------- ### Add Global Using Statement Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/README.md Add this using statement globally in your GlobalUsings.cs file for easy access to the MessagingCenter. ```csharp global using Plugin.Maui.MessagingCenter; ``` -------------------------------- ### Unsubscribe Before Re-subscribing Pattern Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/errors.md This pattern shows how to safely re-subscribe to a message by first unsubscribing from it. This is typically done in OnAppearing and OnDisappearing methods to ensure proper subscription management. ```csharp public partial class MyPage : ContentPage { protected override void OnAppearing() { base.OnAppearing(); // Unsubscribe first in case we were already subscribed MessagingCenter.Unsubscribe(this, "LocationUpdate"); // Now subscribe MessagingCenter.Subscribe(this, "LocationUpdate", (sender, location) => { }); } protected override void OnDisappearing() { base.OnDisappearing(); MessagingCenter.Unsubscribe(this, "LocationUpdate"); } } ``` -------------------------------- ### Mock IMessagingCenter for Unit Tests Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/api-reference/IMessagingCenter.md Provides a mock implementation of IMessagingCenter for use in unit tests. It tracks whether the Send method was called. ```csharp public class MockMessagingCenter : IMessagingCenter { public bool WasSendCalled { get; private set; } public void Send(TSender sender, string message, TArgs args) where TSender : class { WasSendCalled = true; } public void Send(TSender sender, string message) where TSender : class { WasSendCalled = true; } public void Subscribe(object subscriber, string message, Action callback, TSender source = null) where TSender : class { } public void Subscribe(object subscriber, string message, Action callback, TSender source = null) where TSender : class { } public void Unsubscribe(object subscriber, string message) where TSender : class { } public void Unsubscribe(object subscriber, string message) where TSender : class { } } [Fact] public void TestDataService() { var mc = new MockMessagingCenter(); var service = new DataService(mc); service.LoadData(); Assert.True(mc.WasSendCalled); } ``` -------------------------------- ### Sender Filtering for Specific Instances Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/README.md Shows how to subscribe to messages, but only receive them from a specific sender instance, ensuring targeted message handling. ```csharp // Only receive messages from a specific instance var specificViewModel = new MainViewModel(); MessagingCenter.Subscribe(this, "StatusUpdate", (sender, status) => { // Handle status update }, specificViewModel); // Only from this specific instance ``` -------------------------------- ### Mock Messaging Center for Testing Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/OVERVIEW.md Implement the IMessagingCenter interface for unit testing. This mock class tracks if messages have been sent. ```csharp public class MockMessagingCenter : IMessagingCenter { public bool MessageSent { get; private set; } public void Send(TSender sender, string message, TArgs args) where TSender : class { MessageSent = true; } // ... implement other interface methods ... } ``` -------------------------------- ### Send a Message with Arguments Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/README.md Static method to send a message with specific sender and argument types. Requires sender and arguments. ```csharp public static void Send(TSender sender, string message, TArgs args) where TSender : class ``` -------------------------------- ### Unit Test for Data Service Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/OVERVIEW.md A unit test demonstrating how to use the MockMessagingCenter to test a DataService that publishes data. ```csharp [Fact] public void TestDataService() { var mockMc = new MockMessagingCenter(); var service = new DataService(mockMc); service.PublishData(); Assert.True(mockMc.MessageSent); } ``` -------------------------------- ### MessagingCenter Static Methods Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/README.md Provides static methods for sending and subscribing to messages. These methods delegate to an instance of IMessagingCenter. ```APIDOC ## Static Methods (MessagingCenter) ### Send a message with arguments ```csharp public static void Send(TSender sender, string message, TArgs args) where TSender : class ``` ### Send a message without arguments ```csharp public static void Send(TSender sender, string message) where TSender : class ``` ### Subscribe to a message with arguments ```csharp public static void Subscribe(object subscriber, string message, Action callback, TSender source = null) where TSender : class ``` ### Subscribe to a message without arguments ```csharp public static void Subscribe(object subscriber, string message, Action callback, TSender source = null) where TSender : class ``` ### Unsubscribe from a message with arguments ```csharp public static void Unsubscribe(object subscriber, string message) where TSender : class ``` ### Unsubscribe from a message without arguments ```csharp public static void Unsubscribe(object subscriber, string message) where TSender : class ``` ``` -------------------------------- ### Unit Test with Mock Messaging Center Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/COMMON_PATTERNS.md Implement a mock IMessagingCenter to isolate and test components that rely on messaging. This mock captures sent messages for assertion without actual delivery. ```csharp public class MockMessagingCenter : IMessagingCenter { public List<(string message, object args)> SentMessages { get; } = new(); public void Send(TSender sender, string message, TArgs args) where TSender : class { SentMessages.Add((message, args)); } public void Send(TSender sender, string message) where TSender : class { SentMessages.Add((message, null)); } public void Subscribe(object subscriber, string message, Action callback, TSender source = null) where TSender : class { } public void Subscribe(object subscriber, string message, Action callback, TSender source = null) where TSender : class { } public void Unsubscribe(object subscriber, string message) where TSender : class { } public void Unsubscribe(object subscriber, string message) where TSender : class { } } [TestFixture] public class DataServiceTests { [Test] public async Task LoadDataAsync_SendsDataLoadedMessage() { // Arrange var mockMc = new MockMessagingCenter(); var service = new DataService(mockMc, new MockHttpClient()); // Act await service.LoadDataAsync(); // Assert var dataLoadedMessage = mockMc.SentMessages .FirstOrDefault(m => m.message == "DataLoaded"); Assert.That(dataLoadedMessage, Is.Not.Null); } } ``` -------------------------------- ### Subscribe with Arguments Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/api-reference/MessagingCenter.md Subscribes to receive messages with a string key and an argument payload. Use this when your message needs to carry data. The subscription is keyed by subscriber, message key, sender type, and argument type. Duplicate subscriptions to the same message type and key by the same subscriber will throw an InvalidOperationException. ```csharp public static void Subscribe( object subscriber, string message, Action callback, TSender source = null) where TSender : class ``` ```csharp // Subscribe to receive LocationUpdate messages from MainPage with LocationModel data MessagingCenter.Subscribe(this, "LocationUpdate", (sender, location) => { // Handle the location update Console.WriteLine($"Location: {location.City} ({location.Latitude})"); }); // Subscribe to messages from a specific sender instance var specificSender = new MainPage(); MessagingCenter.Subscribe(this, "Status", (sender, status) => { Console.WriteLine($"Status: {status}"); }, source: specificSender); // Only receive from this specific instance ``` -------------------------------- ### Sender Filtering with Specific Instance Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/OVERVIEW.md Demonstrates how to filter messages to only receive them from a specific sender instance using the 'source' parameter in Subscribe. ```csharp var viewModel = new MainViewModel(); // Only receive messages from this specific ViewModel instance MessagingCenter.Subscribe(this, "PropertyChanged", (sender, propertyName) => { Console.WriteLine($"Property changed: {propertyName}"); }, source: viewModel); ``` -------------------------------- ### Send Message with Arguments Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/api-reference/IMessagingCenter.md Publishes a message with a string key and an argument payload. Subscribers can filter by sender type and specific sender object. ```csharp void Send(TSender sender, string message, TArgs args) where TSender : class ``` -------------------------------- ### Page-to-Page Communication: Subscribing to Updates Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/COMMON_PATTERNS.md Subscribe to messages from the detail page on the list page to update the displayed items. Remember to unsubscribe when the page is no longer visible to prevent memory leaks. ```csharp // ListPage.xaml.cs public partial class ListPage : ContentPage { public ListPage() { InitializeComponent(); } protected override void OnAppearing() { base.OnAppearing(); // Listen for updates from DetailPage MessagingCenter.Subscribe(this, "ItemUpdated", (sender, updatedItem) => { var index = Items.IndexOf(updatedItem); if (index >= 0) { Items[index] = updatedItem; } }); } protected override void OnDisappearing() { base.OnDisappearing(); MessagingCenter.Unsubscribe(this, "ItemUpdated"); } } ``` -------------------------------- ### Subscribe to a Message without Arguments Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/README.md Static method to subscribe to a message with a specific sender type, but no arguments. Requires a callback action. ```csharp public static void Subscribe(object subscriber, string message, Action callback, TSender source = null) where TSender : class ``` -------------------------------- ### ViewModel-to-View Communication: Publishing State Changes Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/COMMON_PATTERNS.md Publish state changes from a ViewModel to notify multiple Views. Use `OnPropertyChanged` to ensure UI updates when properties change. ```csharp public class MainViewModel : INotifyPropertyChanged { private string _title = "Default"; public string Title { get => _title; set { if (_title != value) { _title = value; // Notify all listeners MessagingCenter.Send( this, "TitleChanged", _title); OnPropertyChanged(nameof(Title)); } } } public void RefreshData() { var newData = LoadData(); MessagingCenter.Send>( this, "DataRefreshed", newData); } } ``` -------------------------------- ### Original .NET MAUI MessagingCenter Duplicate Subscription Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/OVERVIEW.md Illustrates how the original .NET MAUI MessagingCenter allows duplicate subscriptions to the same message, which can lead to unintended behavior. ```csharp // This is allowed — both handlers will be invoked Subscribe(subscriber, "test", handler1); Subscribe(subscriber, "test", handler2); // OK ``` -------------------------------- ### Unsubscribe-Subscribe Pattern for Revisited Pages Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/errors.md Implement the unsubscribe-subscribe pattern in OnAppearing and OnDisappearing to safely manage subscriptions for pages that are frequently revisited. This ensures that old subscriptions are cleared before new ones are established. ```csharp protected override void OnAppearing() { base.OnAppearing(); // Safe: always unsubscribe first MessagingCenter.Unsubscribe>(this, "ItemsLoaded"); MessagingCenter.Subscribe>(this, "ItemsLoaded", (sender, items) => { }); } protected override void OnDisappearing() { MessagingCenter.Unsubscribe>(this, "ItemsLoaded"); base.OnDisappearing(); } ``` -------------------------------- ### Unsubscribing from Messages Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/README.md Demonstrates the correct way to unsubscribe from messages when a page is disappearing to prevent memory leaks. ```csharp public partial class MyPage : ContentPage { protected override void OnDisappearing() { // Unsubscribe from all messages this page subscribed to MessagingCenter.Unsubscribe(this, "DataUpdated"); MessagingCenter.Unsubscribe(this, "RefreshData"); base.OnDisappearing(); } } ``` -------------------------------- ### MessagingCenter Send and Subscribe with Argument Payload Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/types.md Use these methods when sending or subscribing to messages that include a payload of arguments. The `TSender` type must be a reference type. ```csharp Send(TSender sender, string message, TArgs args) Subscribe(object subscriber, string message, Action callback, TSender source = null) ``` -------------------------------- ### MessagingCenter Static Class Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/types.md The primary static facade for the messaging API. All instance methods delegate to the singleton `MessagingCenter.Instance` of type `IMessagingCenter`. This provides a familiar static API compatible with the original .NET MAUI MessagingCenter while maintaining a clean testable architecture via the `IMessagingCenter` interface. ```APIDOC ## MessagingCenter Static Class ### Description The primary static facade for the messaging API. All instance methods delegate to the singleton `MessagingCenter.Instance` of type `IMessagingCenter`. This provides a familiar static API compatible with the original .NET MAUI MessagingCenter while maintaining a clean testable architecture via the `IMessagingCenter` interface. ### Static Members - **Instance**: Gets the singleton implementation of IMessagingCenter. - **Send(TSender sender, string message, TArgs args)**: Publishes a message with arguments. - **Send(TSender sender, string message)**: Publishes a message without arguments. - **Subscribe(object subscriber, string message, Action callback, TSender source = null)**: Subscribes to messages with arguments. - **Subscribe(object subscriber, string message, Action callback, TSender source = null)**: Subscribes to messages without arguments. - **Unsubscribe(object subscriber, string message)**: Unsubscribes from messages with arguments. - **Unsubscribe(object subscriber, string message)**: Unsubscribes from messages without arguments. ``` -------------------------------- ### Generate Subscription Keys Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/ARCHITECTURE.md Generates unique keys for message subscriptions based on sender type, argument type, and message name. Overloads exist for messages with and without arguments. ```csharp private static string CreateSubscriptionKey(string message) { return $"{typeof(TSender).FullName}:{typeof(TArgs).FullName}:{message}"; } private static string CreateSubscriptionKey(string message) { return $"{typeof(TSender).FullName}:NoArgs:{message}"; } ``` -------------------------------- ### IMessagingCenter Interface Reference Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/MANIFEST.txt Reference for the IMessagingCenter interface, outlining the contract for messaging functionalities. This is useful for dependency injection and mock implementations. ```APIDOC ## IMessagingCenter Interface ### Description Defines the contract for messaging operations, enabling dependency injection and testability. ### Methods #### Send() ### Description Sends a message with arguments to all subscribers. ### Method `Send()` ### Parameters - **TSender** (Type) - The type of the sender. - **TArgs** (Type) - The type of the message arguments. - **messageKey** (string) - The unique key identifying the message. - **sender** (TSender) - The instance of the sender. - **args** (TArgs) - The arguments for the message. #### Send() ### Description Sends a message without arguments to all subscribers. ### Method `Send()` ### Parameters - **TSender** (Type) - The type of the sender. - **messageKey** (string) - The unique key identifying the message. - **sender** (TSender) - The instance of the sender. #### Subscribe() ### Description Subscribes a callback to receive messages with arguments. ### Method `Subscribe()` ### Parameters - **TSender** (Type) - The type of the sender. - **TArgs** (Type) - The type of the message arguments. - **messageKey** (string) - The unique key identifying the message. - **sender** (TSender) - The sender instance to filter messages from. - **callback** (Action) - The action to execute when the message is received. #### Subscribe() ### Description Subscribes a callback to receive messages without arguments. ### Method `Subscribe()` ### Parameters - **TSender** (Type) - The type of the sender. - **messageKey** (string) - The unique key identifying the message. - **sender** (TSender) - The sender instance to filter messages from. - **callback** (Action) - The action to execute when the message is received. #### Unsubscribe() ### Description Unsubscribes a specific callback for messages with arguments. ### Method `Unsubscribe()` ### Parameters - **TSender** (Type) - The type of the sender. - **TArgs** (Type) - The type of the message arguments. - **messageKey** (string) - The unique key identifying the message. - **sender** (TSender) - The sender instance to filter messages from. #### Unsubscribe() ### Description Unsubscribes a specific callback for messages without arguments. ### Method `Unsubscribe()` ### Parameters - **TSender** (Type) - The type of the sender. - **messageKey** (string) - The unique key identifying the message. - **sender** (TSender) - The sender instance to filter messages from. ### Error Handling - **ArgumentNullException**: Thrown if a required parameter is null. - **InvalidOperationException**: Thrown for duplicate subscriptions. ``` -------------------------------- ### Page-to-Page Communication: Sending Updates Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/COMMON_PATTERNS.md Send a message from a detail page to a list page when an item is updated. Ensure to navigate back after sending the message. ```csharp // DetailPage.xaml.cs public partial class DetailPage : ContentPage { private Item _currentItem; private void OnSaveClicked() { // Send a message back to the list page MessagingCenter.Send(this, "ItemUpdated", _currentItem); // Navigate back await Navigation.PopAsync(); } } ``` -------------------------------- ### Service-to-UI Communication: Publishing Background Events Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/COMMON_PATTERNS.md Publish events from a background service to notify the UI about changes, such as location updates. The service should run asynchronously and periodically send updates. ```csharp public class LocationService { public async Task StartTrackingAsync() { while (true) { var location = await GetCurrentLocationAsync(); // Notify any listeners about location updates MessagingCenter.Send( this, "LocationUpdated", location); await Task.Delay(5000); } } } ``` -------------------------------- ### Subscribe to Messages with Arguments Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/api-reference/IMessagingCenter.md Registers a callback to receive messages identified by a string key and carrying an argument payload. Duplicate subscriptions for the same subscriber, message key, sender type, and argument type are prevented and will throw an InvalidOperationException. An optional sender filter can be provided. ```csharp void Subscribe( object subscriber, string message, Action callback, TSender source = null) where TSender : class ``` -------------------------------- ### Duplicate Subscription Attempt Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/errors.md This scenario demonstrates how attempting to subscribe the same object to the same message key twice without unsubscribing first will result in an InvalidOperationException. ```csharp var subscriber = new object(); // First subscription — succeeds MessagingCenter.Subscribe(subscriber, "LocationUpdate", (sender, location) => { }); // Second subscription to the SAME message type and key — throws InvalidOperationException MessagingCenter.Subscribe(subscriber, "LocationUpdate", (sender, location) => { }); // Exception: "The target recipient has already subscribed to the target message." ``` -------------------------------- ### Handle duplicate subscriptions Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/OVERVIEW.md Add proper unsubscribe logic to prevent InvalidOperationException when subscribing to the same message multiple times. ```csharp MessagingCenter.Unsubscribe(this, "key"); MessagingCenter.Subscribe(this, "key", handler); ``` -------------------------------- ### Closure Callback with Strong Reference Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/ARCHITECTURE.md This snippet demonstrates a scenario where a callback is a closure that captures the subscriber. In such cases, a strong reference is maintained to ensure the subscriber is not garbage collected while subscribed. This reference is created upon subscription and removed upon explicit unsubscription. ```csharp Subscribe(subscriber, "msg", sender => subscriber.Update()); ``` -------------------------------- ### IMessagingCenter Interface Methods Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/README.md Defines the contract for the messaging center, providing methods for sending, subscribing, and unsubscribing from messages. These methods are implemented by the MessagingCenter static class's underlying instance. ```APIDOC ## Interface Methods (IMessagingCenter) Provides the same six methods as the MessagingCenter static class: - `Send(sender, message, args)` - `Send(sender, message)` - `Subscribe(subscriber, message, callback, source)` - `Subscribe(subscriber, message, callback, source)` - `Unsubscribe(subscriber, message)` - `Unsubscribe(subscriber, message)` ``` -------------------------------- ### Plugin.Maui.MessagingCenter Duplicate Subscription Exception Source: https://github.com/jfversluis/plugin.maui.messagingcenter/blob/main/_autodocs/OVERVIEW.md Demonstrates that Plugin.Maui.MessagingCenter throws an InvalidOperationException when attempting to subscribe to the same message twice with the same subscriber. ```csharp // This throws InvalidOperationException Subscribe(subscriber, "test", handler1); Subscribe(subscriber, "test", handler2); // Throws! ```