Files
dotnet/Microsoft.Toolkit.Mvvm/ComponentModel/ViewModelBase.cs
T
Sergio Pedri 8b40852908 Renamed Services namespace to DependencyInjection
This follows the naming from Microsoft.Extensions.DependencyInjection
2020-04-17 12:25:16 +02:00

184 lines
7.5 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
// Original file header:
// ****************************************************************************
// <copyright file="ViewModelBase.cs" company="GalaSoft Laurent Bugnion">
// Copyright © GalaSoft Laurent Bugnion 2009-2016
// </copyright>
// ****************************************************************************
// <author>Laurent Bugnion</author>
// <email>laurent@galasoft.ch</email>
// <date>22.4.2009</date>
// <project>GalaSoft.MvvmLight</project>
// <web>http://www.mvvmlight.net</web>
// <license>
// See license.txt in this project or http://www.galasoft.ch/license_MIT.txt
// </license>
// <LastBaseLevel>BL0014</LastBaseLevel>
// ****************************************************************************
using System.Runtime.CompilerServices;
using Microsoft.Toolkit.Mvvm.DependencyInjection;
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"/>
/// and <see cref="DependencyInjection.Ioc.Default"/> services to perform operations.
/// </remarks>
protected ViewModelBase()
: this(Messaging.Messenger.Default, DependencyInjection.Ioc.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)
: this(messenger, DependencyInjection.Ioc.Default)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ViewModelBase"/> class.
/// </summary>
/// <param name="ioc">The optional <see cref="IIoc"/> instance to use to retrieve services.</param>
protected ViewModelBase(IIoc ioc)
: this(Messaging.Messenger.Default, ioc)
{
}
/// <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>
/// <param name="ioc">The optional <see cref="IIoc"/> instance to use to retrieve services.</param>
protected ViewModelBase(IMessenger messenger, IIoc ioc)
{
Messenger = messenger;
Ioc = ioc;
}
/// <summary>
/// Gets the <see cref="IMessenger"/> instance in use.
/// </summary>
protected IMessenger Messenger { get; }
/// <summary>
/// Gets the <see cref="IIoc"/> instance in use.
/// </summary>
protected IIoc Ioc { 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))
{
if (value)
{
OnActivate();
}
else
{
OnDeactivate();
}
}
}
}
/// <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>
protected virtual void OnActivate()
{
}
/// <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 (with no token).</remarks>
protected virtual void OnDeactivate()
{
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;
}
}
}