// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
///
/// A base class for observable objects that also acts as recipients for messages. This class is an extension of
/// ObservableObject which also provides built-in support to use the IMessenger type.
///
public abstract class ObservableRecipient
{
///
/// Initializes a new instance of the class.
///
///
/// This constructor will produce an instance that will use the instance
/// to perform requested operations. It will also be available locally through the property.
///
protected ObservableRecipient()
: this(global::CommunityToolkit.Mvvm.Messaging.WeakReferenceMessenger.Default)
{
}
///
/// Initializes a new instance of the class.
///
/// The instance to use to send messages.
protected ObservableRecipient(global::CommunityToolkit.Mvvm.Messaging.IMessenger messenger)
{
Messenger = messenger;
}
///
/// Gets the instance in use.
///
protected global::CommunityToolkit.Mvvm.Messaging.IMessenger Messenger { get; }
private bool isActive;
///
/// Gets or sets a value indicating whether the current view model is currently active.
///
public bool IsActive
{
get => this.isActive;
[global::System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode(
"When this property is set to true, the OnActivated() method will be invoked, which will register all necessary message handlers for this recipient. " +
"This method requires the generated CommunityToolkit.Mvvm.Messaging.__Internals.__IMessengerExtensions type not to be removed to use the fast path. " +
"If this type is removed by the linker, or if the target recipient was created dynamically and was missed by the source generator, a slower fallback " +
"path using a compiled LINQ expression will be used. This will have more overhead in the first invocation of this method for any given recipient type. " +
"Alternatively, OnActivated() can be manually overwritten, and registration can be done individually for each required message for this recipient.")]
set
{
if (SetProperty(ref this.isActive, value, true))
{
if (value)
{
OnActivated();
}
else
{
OnDeactivated();
}
}
}
}
///
/// Invoked whenever the property is set to .
/// Use this method to register to messages and do other initialization for this instance.
///
[global::System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode(
"This method requires the generated CommunityToolkit.Mvvm.Messaging.__Internals.__IMessengerExtensions type not to be removed to use the fast path. " +
"If this type is removed by the linker, or if the target recipient was created dynamically and was missed by the source generator, a slower fallback " +
"path using a compiled LINQ expression will be used. This will have more overhead in the first invocation of this method for any given recipient type. " +
"Alternatively, OnActivated() can be manually overwritten, and registration can be done individually for each required message for this recipient.")]
protected virtual void OnActivated()
{
global::CommunityToolkit.Mvvm.Messaging.IMessengerExtensions.RegisterAll(Messenger, this);
}
///
/// Invoked whenever the property is set to .
/// Use this method to unregister from messages and do general cleanup for this instance.
///
protected virtual void OnDeactivated()
{
Messenger.UnregisterAll(this);
}
///
/// Broadcasts a with the specified
/// parameters, without using any particular token (so using the default channel).
///
/// The type of the property that changed.
/// The value of the property before it changed.
/// The value of the property after it changed.
/// The name of the property that changed.
///
/// You should override this method if you wish to customize the channel being
/// used to send the message (eg. if you need to use a specific token for the channel).
///
protected virtual void Broadcast(T oldValue, T newValue, string? propertyName)
{
var message = new global::CommunityToolkit.Mvvm.Messaging.Messages.PropertyChangedMessage(this, propertyName, oldValue, newValue);
_ = global::CommunityToolkit.Mvvm.Messaging.IMessengerExtensions.Send(Messenger, message);
}
///
/// Compares the current and new values for a given property. If the value has changed,
/// raises the event, updates the property with
/// the new value, then raises the event.
///
/// The type of the property that changed.
/// The field storing the property's value.
/// The property's value after the change occurred.
/// If , will also be invoked.
/// (optional) The name of the property that changed.
/// if the property was changed, otherwise.
///
/// This method is just like , just with the addition
/// of the parameter. As such, following the behavior of the base method,
/// the and events
/// are not raised if the current and new value for the target property are the same.
///
protected bool SetProperty([global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull("newValue")] ref T field, T newValue, bool broadcast, [global::System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null)
{
T oldValue = field;
bool propertyChanged = SetProperty(ref field, newValue, propertyName);
if (propertyChanged && broadcast)
{
Broadcast(oldValue, newValue, propertyName);
}
return propertyChanged;
}
///
/// Compares the current and new values for a given property. If the value has changed,
/// raises the event, updates the property with
/// the new value, then raises the event.
/// See additional notes about this overload in .
///
/// The type of the property that changed.
/// The field storing the property's value.
/// The property's value after the change occurred.
/// The instance to use to compare the input values.
/// If , will also be invoked.
/// (optional) The name of the property that changed.
/// if the property was changed, otherwise.
protected bool SetProperty([global::System.Diagnostics.CodeAnalysis.NotNullIfNotNull("newValue")] ref T field, T newValue, global::System.Collections.Generic.IEqualityComparer comparer, bool broadcast, [global::System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null)
{
T oldValue = field;
bool propertyChanged = SetProperty(ref field, newValue, comparer, propertyName);
if (propertyChanged && broadcast)
{
Broadcast(oldValue, newValue, propertyName);
}
return propertyChanged;
}
///
/// Compares the current and new values for a given property. If the value has changed,
/// raises the event, updates the property with
/// the new value, then raises the event. Similarly to
/// the method, this overload should only be
/// used when can't be used directly.
///
/// The type of the property that changed.
/// The current property value.
/// The property's value after the change occurred.
/// A callback to invoke to update the property value.
/// If , will also be invoked.
/// (optional) The name of the property that changed.
/// if the property was changed, otherwise.
///
/// This method is just like , just with the addition
/// of the parameter. As such, following the behavior of the base method,
/// the and events
/// are not raised if the current and new value for the target property are the same.
///
protected bool SetProperty(T oldValue, T newValue, global::System.Action callback, bool broadcast, [global::System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null)
{
bool propertyChanged = SetProperty(oldValue, newValue, callback, propertyName);
if (propertyChanged && broadcast)
{
Broadcast(oldValue, newValue, propertyName);
}
return propertyChanged;
}
///
/// Compares the current and new values for a given property. If the value has changed,
/// raises the event, updates the property with
/// the new value, then raises the event.
/// See additional notes about this overload in .
///
/// The type of the property that changed.
/// The current property value.
/// The property's value after the change occurred.
/// The instance to use to compare the input values.
/// A callback to invoke to update the property value.
/// If , will also be invoked.
/// (optional) The name of the property that changed.
/// if the property was changed, otherwise.
protected bool SetProperty(T oldValue, T newValue, global::System.Collections.Generic.IEqualityComparer comparer, global::System.Action callback, bool broadcast, [global::System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null)
{
bool propertyChanged = SetProperty(oldValue, newValue, comparer, callback, propertyName);
if (propertyChanged && broadcast)
{
Broadcast(oldValue, newValue, propertyName);
}
return propertyChanged;
}
///
/// Compares the current and new values for a given nested property. If the value has changed,
/// raises the event, updates the property and then raises the
/// event. The behavior mirrors that of
/// , with the difference being that this
/// method is used to relay properties from a wrapped model in the current instance. For more info, see the docs for
/// .
///
/// The type of model whose property (or field) to set.
/// The type of property (or field) to set.
/// The current property value.
/// The property's value after the change occurred.
/// The model
/// The callback to invoke to set the target property value, if a change has occurred.
/// If , will also be invoked.
/// (optional) The name of the property that changed.
/// if the property was changed, otherwise.
protected bool SetProperty(T oldValue, T newValue, TModel model, global::System.Action callback, bool broadcast, [global::System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null)
where TModel : class
{
bool propertyChanged = SetProperty(oldValue, newValue, model, callback, propertyName);
if (propertyChanged && broadcast)
{
Broadcast(oldValue, newValue, propertyName);
}
return propertyChanged;
}
///
/// Compares the current and new values for a given nested property. If the value has changed,
/// raises the event, updates the property and then raises the
/// event. The behavior mirrors that of
/// ,
/// with the difference being that this method is used to relay properties from a wrapped model in the
/// current instance. For more info, see the docs for
/// .
///
/// The type of model whose property (or field) to set.
/// The type of property (or field) to set.
/// The current property value.
/// The property's value after the change occurred.
/// The instance to use to compare the input values.
/// The model
/// The callback to invoke to set the target property value, if a change has occurred.
/// If , will also be invoked.
/// (optional) The name of the property that changed.
/// if the property was changed, otherwise.
protected bool SetProperty(T oldValue, T newValue, global::System.Collections.Generic.IEqualityComparer comparer, TModel model, global::System.Action callback, bool broadcast, [global::System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null)
where TModel : class
{
bool propertyChanged = SetProperty(oldValue, newValue, comparer, model, callback, propertyName);
if (propertyChanged && broadcast)
{
Broadcast(oldValue, newValue, propertyName);
}
return propertyChanged;
}
}