mirror of
https://github.com/CommunityToolkit/dotnet.git
synced 2026-10-26 01:53:02 +08:00
195 lines
9.0 KiB
C#
195 lines
9.0 KiB
C#
// 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.
|
|
|
|
#pragma warning disable SA1512
|
|
|
|
// This file is inspired from the MvvmLight libray (lbugnion/mvvmlight),
|
|
// more info in ThirdPartyNotices.txt in the root of the project.
|
|
|
|
using System;
|
|
using System.Runtime.CompilerServices;
|
|
using Microsoft.Toolkit.Mvvm.Messaging;
|
|
using Microsoft.Toolkit.Mvvm.Messaging.Messages;
|
|
|
|
namespace Microsoft.Toolkit.Mvvm.ComponentModel
|
|
{
|
|
/// <summary>
|
|
/// A base class for viewmodels.
|
|
/// </summary>
|
|
public abstract class ViewModelBase : ObservableObject
|
|
{
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="ViewModelBase"/> class.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This constructor will produce an instance that will use the <see cref="Messaging.Messenger.Default"/> instance
|
|
/// to perform requested operations. It will also be available locally through the <see cref="Messenger"/> property.
|
|
/// </remarks>
|
|
protected ViewModelBase()
|
|
: this(Messaging.Messenger.Default)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="ViewModelBase"/> class.
|
|
/// </summary>
|
|
/// <param name="messenger">The <see cref="IMessenger"/> instance to use to send messages.</param>
|
|
protected ViewModelBase(IMessenger messenger)
|
|
{
|
|
Messenger = messenger;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the <see cref="IMessenger"/> instance in use.
|
|
/// </summary>
|
|
protected IMessenger Messenger { get; }
|
|
|
|
private bool isActive;
|
|
|
|
/// <summary>
|
|
/// Gets or sets a value indicating whether the current view model is currently active.
|
|
/// </summary>
|
|
public bool IsActive
|
|
{
|
|
get => this.isActive;
|
|
set
|
|
{
|
|
if (Set(ref this.isActive, value, true))
|
|
{
|
|
if (value)
|
|
{
|
|
OnActivated();
|
|
}
|
|
else
|
|
{
|
|
OnDeactivated();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Raised whenever the <see cref="IsActive"/> property is set to <see langword="true"/>.
|
|
/// Use this method to register to messages and do other initialization for this instance.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The base implementation registers all messages for this recipients that have been declared
|
|
/// explicitly through the <see cref="ISubscriber{TMessage}"/> interface, using the default channel.
|
|
/// For more details on how this works, see the <see cref="MessengerExtensions.Register"/> method.
|
|
/// If you need more fine tuned control, want to register messages individually or just prefer
|
|
/// the lambda-style syntax for message registration, override this method and register manually.
|
|
/// </remarks>
|
|
protected virtual void OnActivated()
|
|
{
|
|
Messenger.Register(this);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Raised whenever the <see cref="IsActive"/> property is set to <see langword="false"/>.
|
|
/// Use this method to unregister from messages and do general cleanup for this instance.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The base implementation unregisters all messages for this recipient. It does so by
|
|
/// invoking <see cref="IMessenger.Unregister(object)"/>, which removes all registered
|
|
/// handlers for a given subscriber, regardless of what token was used to register them.
|
|
/// That is, all registered handlers across all subscription channels will be removed.
|
|
/// </remarks>
|
|
protected virtual void OnDeactivated()
|
|
{
|
|
Messenger.Unregister(this);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Broadcasts a <see cref="PropertyChangedMessage{T}"/> with the specified
|
|
/// parameters, without using any particular token (so using the default channel).
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of the property that changed.</typeparam>
|
|
/// <param name="oldValue">The value of the property before it changed.</param>
|
|
/// <param name="newValue">The value of the property after it changed.</param>
|
|
/// <param name="propertyName">The name of the property that changed.</param>
|
|
/// <remarks>
|
|
/// 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).
|
|
/// </remarks>
|
|
protected virtual void Broadcast<T>(T oldValue, T newValue, string propertyName)
|
|
{
|
|
var message = new PropertyChangedMessage<T>(this, propertyName, oldValue, newValue);
|
|
|
|
Messenger.Send(message);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compares the current and new values for a given property. If the value has changed,
|
|
/// raises the <see cref="ObservableObject.PropertyChanging"/> event, updates the property with
|
|
/// the new value, then raises the <see cref="ObservableObject.PropertyChanged"/> event.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of the property that changed.</typeparam>
|
|
/// <param name="field">The field storing the property's value.</param>
|
|
/// <param name="newValue">The property's value after the change occurred.</param>
|
|
/// <param name="broadcast">If <see langword="true"/>, <see cref="Broadcast{T}"/> will also be invoked.</param>
|
|
/// <param name="propertyName">(optional) The name of the property that changed.</param>
|
|
/// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns>
|
|
/// <remarks>
|
|
/// This method is just like <see cref="ObservableObject.Set{T}(ref T,T,string)"/>, just with the addition
|
|
/// of the <paramref name="broadcast"/> parameter. As such, following the behavior of the base method,
|
|
/// the <see cref="ObservableObject.PropertyChanging"/> and <see cref="ObservableObject.PropertyChanged"/> events
|
|
/// are not raised if the current and new value for the target property are the same.
|
|
/// </remarks>
|
|
protected bool Set<T>(ref T field, T newValue, bool broadcast, [CallerMemberName] string propertyName = null!)
|
|
{
|
|
if (!broadcast)
|
|
{
|
|
return Set(ref field, newValue, propertyName);
|
|
}
|
|
|
|
T oldValue = field;
|
|
|
|
if (Set(ref field, newValue, propertyName))
|
|
{
|
|
Broadcast(oldValue, newValue, propertyName);
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Compares the current and new values for a given property. If the value has changed,
|
|
/// raises the <see cref="ObservableObject.PropertyChanging"/> event, updates the property with
|
|
/// the new value, then raises the <see cref="ObservableObject.PropertyChanged"/> event. Similarly to
|
|
/// the <see cref="ObservableObject.Set{T}(T,T,Action{T},string)"/> method, this overload should only be
|
|
/// used when <see cref="ObservableObject.Set{T}(ref T,T,string)"/> can't be used directly.
|
|
/// </summary>
|
|
/// <typeparam name="T">The type of the property that changed.</typeparam>
|
|
/// <param name="oldValue">The current property value.</param>
|
|
/// <param name="newValue">The property's value after the change occurred.</param>
|
|
/// <param name="callback">A callback to invoke to update the property value.</param>
|
|
/// <param name="broadcast">If <see langword="true"/>, <see cref="Broadcast{T}"/> will also be invoked.</param>
|
|
/// <param name="propertyName">(optional) The name of the property that changed.</param>
|
|
/// <returns><see langword="true"/> if the property was changed, <see langword="false"/> otherwise.</returns>
|
|
/// <remarks>
|
|
/// This method is just like <see cref="ObservableObject.Set{T}(T,T,Action{T},string)"/>, just with the addition
|
|
/// of the <paramref name="broadcast"/> parameter. As such, following the behavior of the base method,
|
|
/// the <see cref="ObservableObject.PropertyChanging"/> and <see cref="ObservableObject.PropertyChanged"/> events
|
|
/// are not raised if the current and new value for the target property are the same.
|
|
/// </remarks>
|
|
protected bool Set<T>(T oldValue, T newValue, Action<T> callback, bool broadcast, [CallerMemberName] string propertyName = null!)
|
|
{
|
|
if (!broadcast)
|
|
{
|
|
return Set(oldValue, newValue, callback, propertyName);
|
|
}
|
|
|
|
if (Set(oldValue, newValue, callback, propertyName))
|
|
{
|
|
Broadcast(oldValue, newValue, propertyName);
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
} |