dbMango/Rms.Risk.Mango.Pivot.Core/Models/NotifyPropertyChangedBase.cs
Alexander Shabarshov 2a7a24c9e7 Initial contribution
2025-11-03 14:43:26 +00:00

179 lines
5.3 KiB
C#

/*
* dbMango
*
* Copyright 2025 Deutsche Bank AG
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.ComponentModel;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
namespace Rms.Risk.Mango.Pivot.Core.Models;
public interface IMutable
{
bool IsBusy { get; }
void Mute();
void Unmute();
}
public class NotifyPropertyChangedBase : INotifyPropertyChanged, IMutable
{
private static Action<Action> _invokeWrapper = action => action?.Invoke();
/// <summary>
/// For WPF applications call:
/// NotifyPropertyChangedBase.SetInvokeWrapper( Application.Current.Dispatcher.Invoke );
/// </summary>
/// <param name="invokeWrapper"></param>
public static void SetInvokeWrapper(Action<Action> invokeWrapper)
=> _invokeWrapper = invokeWrapper;
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler? PropertyChanged;
#endregion
/// <summary>
/// Returns the name of a property dynamically using an expression tree without requiring an instance
/// usage: GetPropertyName@gt;MyClass@lt;( (MyClass c) => c.MyProperty) returns "MyProperty"
/// </summary>
public static string GetPropertyName<TModel, TProperty>(Expression<Func<TModel, TProperty>> property)
{
var lambda = (LambdaExpression)property;
MemberExpression memberExpression;
if (lambda.Body is UnaryExpression body)
{
var unaryExpression = body;
memberExpression = (MemberExpression)unaryExpression.Operand;
}
else
{
memberExpression = (MemberExpression)lambda.Body;
}
return memberExpression.Member.Name;
}
/// <summary>
/// Returns the name of a property dynamically using an expression tree
/// usage: GetPropertyName( () => someinstance.MyProperty) returns "MyProperty"
/// </summary>
public static string GetPropertyName<T>(Expression<Func<T>> property)
{
var lambda = (LambdaExpression)property;
MemberExpression memberExpression;
if (lambda.Body is UnaryExpression body)
{
var unaryExpression = body;
memberExpression = (MemberExpression)unaryExpression.Operand;
}
else
{
memberExpression = (MemberExpression)lambda.Body;
}
return memberExpression.Member.Name;
}
/// <summary>
/// Overriden by subclasses, which may way want to to enable/diable the notification event.
/// Called before every event notification
/// </summary>
/// <returns></returns>
protected virtual bool AllowPropertyChanged() => true;
/// <summary>
/// Fires the property changed event
/// Dynamically generates the property name using an expression tree
/// usage: OnPropertyChanged( (MyClass m) => m.MyProperty)
/// </summary>
protected void OnPropertyChanged<TModel, TProperty>(Expression<Func<TModel, TProperty>> property)
{
var e = new PropertyChangedEventArgs(GetPropertyName(property));
OnPropertyChanged(e);
}
/// <summary>
/// Fires the property changed event
/// Dynamically generates the property name using an expression tree
/// usage: OnPropertyChanged( () => MyProperty)
/// </summary>
protected void OnPropertyChanged<T>(Expression<Func<T>> property)
{
var e = new PropertyChangedEventArgs(GetPropertyName(property));
OnPropertyChanged(e);
}
/// <summary>
/// Fire the notify property changed event with a static property name
/// No not supply propName as it'll be automatically filled in
/// </summary>
protected void OnPropertyChanged([CallerMemberName] string propName = "")
{
var e = new PropertyChangedEventArgs(propName);
OnPropertyChanged(e);
}
private void OnPropertyChanged(PropertyChangedEventArgs e)
{
// if (IsBusy)
// return;
var pc = PropertyChanged;
if (pc != null && AllowPropertyChanged())
{
_invokeWrapper( () => pc(this, e) );
}
}
public bool IsBusy
{
get => _muteCount > 0;
set
{
if (value)
Mute();
else
Unmute();
}
}
private int _muteCount;
public virtual void Mute()
{
_muteCount += 1;
PropertyChanged?.Invoke(this, new(nameof(IsBusy)));
}
public virtual void Unmute()
{
_muteCount -= 1;
PropertyChanged?.Invoke(this, new(nameof(IsBusy)));
if (_muteCount < 0)
{
#if DEBUG
throw new ApplicationException("Mute count becomes negative");
#else
_muteCount = 0;
#endif
}
}
}