<commit_before>﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Windows;

namespace NorthHorizon.Samples.InpcTemplate
{
    /// <summary>
    /// Provides a basic implementation for <see cref="INotifyPropertyChanged"/> and <see cref="INotifyPropertyChanging"/>.
    /// </summary>
    public abstract class BindableBase : INotifyPropertyChanged, INotifyPropertyChanging
    {
        /// <summary>
        /// Occurs when a property value changes.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged = delegate { };

        /// <summary>
        /// Occurs when a property value is changing.
        /// </summary>
        public event PropertyChangingEventHandler PropertyChanging = delegate { };

        /// <summary>
        /// Assigns the specified value to the specified backing store if a change has
        /// been made and, optionally, raises callbacks before and after.
        /// </summary>
        /// <typeparam name="T">The type of the property.</typeparam>
        /// <param name="backingStore">The backing store.</param>
        /// <param name="value">The new value.</param>
        /// <param name="propertyName">The name of the property.</param>
        /// <param name="onChanged">An optional callback to raise just before <see cref="PropertyChanged"/>.</param>
        /// <param name="onChanging">An optional callback to raise just before <see cref="PropertyChanging"/>.</param>
        /// <param name="coerceValue">An optional callback to coerce values before they are set.</param>
        protected void SetProperty<T>(ref T backingStore, T value, Action onChanged = null, Action<T> onChanging = null, Func<T, T> coerceValue = null, [CallerMemberName]string propertyName = null)
        {
            if (string.IsNullOrEmpty(propertyName)) throw new ArgumentNullException("propertyName");
            VerifyCallerIsProperty(propertyName);

            var effectiveValue = coerceValue != null ? coerceValue(value) : value;

            if (EqualityComparer<T>.Default.Equals(backingStore, effectiveValue))
            {
                // If we coerced this value and the coerced value is not equal to the original, we need to
                // send a fake PropertyChanged event to notify WPF that this value isn't what it thinks it is.
                if (coerceValue != null && !EqualityComparer<T>.Default.Equals(value, effectiveValue))
                    PropertyChangedEventManagerProxy.Instance.RaisePropertyChanged(this, propertyName);

                return;
            }

            if (onChanging != null) onChanging(effectiveValue);

            OnPropertyChanging(propertyName);

            var oldValue = backingStore;
            backingStore = effectiveValue;

            if (onChanged != null) onChanged();

            OnPropertyChanged(propertyName, oldValue, effectiveValue);
        }

        [Conditional("DEBUG")]
        private void VerifyCallerIsProperty(string propertyName)
        {
            var stackTrace = new StackTrace();
            var frame = stackTrace.GetFrames()[2];
            var caller = frame.GetMethod();

            // Explicitly implemented interface props will show the fullname here. Need to trim off the front for a clean compare.
            var callerName = caller.IsHideBySig ? caller.Name.Substring(caller.Name.LastIndexOf('.') + 1) : caller.Name;

            if (!callerName.Equals("set_" + propertyName, StringComparison.InvariantCulture))
                throw new InvalidOperationException(string.Format("Called SetProperty for {0} from {1}", propertyName, caller.Name));
        }

        /// <summary>
        /// Raises the <see cref="E:PropertyChanged"/> event.
        /// </summary>
        /// <param name="propertyName">The name of the property.</param>
        protected void OnPropertyChanged(string propertyName)
        {
            OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
        }

        /// <summary>
        /// Raises the <see cref="E:PropertyChanged"/> event.
        /// </summary>
        /// <param name="propertyName">The name of the property.</param>
        /// <param name="oldValue">The old value of the property.</param>
        /// <param name="newValue">The new value of the property.</param>
        protected void OnPropertyChanged<T>(string propertyName, T oldValue, T newValue)
        {
            OnPropertyChanged(new PropertyChangedEventArgs<T>(propertyName, oldValue, newValue));
        }

        /// <summary>
        /// Raises the <see cref="E:PropertyChanged"/> event.
        /// </summary>
        /// <param name="args">The <see cref="System.ComponentModel.PropertyChangedEventArgs"/> instance containing the event data.</param>
        protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
        {
            PropertyChanged(this, args);
        }

        /// <summary>
        /// Raises the <see cref="E:PropertyChanging"/> event.
        /// </summary>
        /// <param name="propertyName">The name of the property.</param>
        protected virtual void OnPropertyChanging(string propertyName)
        {
            PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
        }

        private class PropertyChangedEventManagerProxy
        {
            private readonly NotifyPropertyChangedProxy _notifyPropertyChangedProxy;

            // We need to hold on to this ref to keep it from getting GC'd
            private readonly IWeakEventListener _weakEventListener;

            private PropertyChangedEventManagerProxy()
            {
                _notifyPropertyChangedProxy = new NotifyPropertyChangedProxy();
                _weakEventListener = new WeakListenerStub();

                PropertyChangedEventManager.AddListener(_notifyPropertyChangedProxy, _weakEventListener, string.Empty);
            }

            public void RaisePropertyChanged(object sender, string propertyName)
            {
                _notifyPropertyChangedProxy.Raise(sender, new PropertyChangedEventArgs(propertyName));
            }

            private static PropertyChangedEventManagerProxy _instance;
            public static PropertyChangedEventManagerProxy Instance { get { return _instance ?? (_instance = new PropertyChangedEventManagerProxy()); } }

            private class NotifyPropertyChangedProxy : INotifyPropertyChanged
            {
                public event PropertyChangedEventHandler PropertyChanged = delegate { };

                public void Raise(object sender, PropertyChangedEventArgs e)
                {
                    PropertyChanged(sender, e);
                }
            }

            private class WeakListenerStub : IWeakEventListener
            {
                public bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e) { return false; }
            }
        }
    }
}
<commit_msg>Removed VerifyCallerIsProperty from BindableBase as CallerMemberNameAttribute should take care of that<commit_after>﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Windows;

namespace NorthHorizon.Samples.InpcTemplate
{
    /// <summary>
    /// Provides a basic implementation for <see cref="INotifyPropertyChanged"/> and <see cref="INotifyPropertyChanging"/>.
    /// </summary>
    public abstract class BindableBase : INotifyPropertyChanged, INotifyPropertyChanging
    {
        /// <summary>
        /// Occurs when a property value changes.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged = delegate { };

        /// <summary>
        /// Occurs when a property value is changing.
        /// </summary>
        public event PropertyChangingEventHandler PropertyChanging = delegate { };

        /// <summary>
        /// Assigns the specified value to the specified backing store if a change has
        /// been made and, optionally, raises callbacks before and after.
        /// </summary>
        /// <typeparam name="T">The type of the property.</typeparam>
        /// <param name="backingStore">The backing store.</param>
        /// <param name="value">The new value.</param>
        /// <param name="propertyName">The name of the property.</param>
        /// <param name="onChanged">An optional callback to raise just before <see cref="PropertyChanged"/>.</param>
        /// <param name="onChanging">An optional callback to raise just before <see cref="PropertyChanging"/>.</param>
        /// <param name="coerceValue">An optional callback to coerce values before they are set.</param>
        protected void SetProperty<T>(ref T backingStore, T value, Action onChanged = null, Action<T> onChanging = null, Func<T, T> coerceValue = null, [CallerMemberName]string propertyName = null)
        {
            if (string.IsNullOrEmpty(propertyName)) throw new ArgumentNullException("propertyName");

            var effectiveValue = coerceValue != null ? coerceValue(value) : value;

            if (EqualityComparer<T>.Default.Equals(backingStore, effectiveValue))
            {
                // If we coerced this value and the coerced value is not equal to the original, we need to
                // send a fake PropertyChanged event to notify WPF that this value isn't what it thinks it is.
                if (coerceValue != null && !EqualityComparer<T>.Default.Equals(value, effectiveValue))
                    PropertyChangedEventManagerProxy.Instance.RaisePropertyChanged(this, propertyName);

                return;
            }

            if (onChanging != null) onChanging(effectiveValue);

            OnPropertyChanging(propertyName);

            var oldValue = backingStore;
            backingStore = effectiveValue;

            if (onChanged != null) onChanged();

            OnPropertyChanged(propertyName, oldValue, effectiveValue);
        }

        /// <summary>
        /// Raises the <see cref="E:PropertyChanged"/> event.
        /// </summary>
        /// <param name="propertyName">The name of the property.</param>
        protected void OnPropertyChanged(string propertyName)
        {
            OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
        }

        /// <summary>
        /// Raises the <see cref="E:PropertyChanged"/> event.
        /// </summary>
        /// <param name="propertyName">The name of the property.</param>
        /// <param name="oldValue">The old value of the property.</param>
        /// <param name="newValue">The new value of the property.</param>
        protected void OnPropertyChanged<T>(string propertyName, T oldValue, T newValue)
        {
            OnPropertyChanged(new PropertyChangedEventArgs<T>(propertyName, oldValue, newValue));
        }

        /// <summary>
        /// Raises the <see cref="E:PropertyChanged"/> event.
        /// </summary>
        /// <param name="args">The <see cref="System.ComponentModel.PropertyChangedEventArgs"/> instance containing the event data.</param>
        protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
        {
            PropertyChanged(this, args);
        }

        /// <summary>
        /// Raises the <see cref="E:PropertyChanging"/> event.
        /// </summary>
        /// <param name="propertyName">The name of the property.</param>
        protected virtual void OnPropertyChanging(string propertyName)
        {
            PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
        }

        private class PropertyChangedEventManagerProxy
        {
            private readonly NotifyPropertyChangedProxy _notifyPropertyChangedProxy;

            // We need to hold on to this ref to keep it from getting GC'd
            private readonly IWeakEventListener _weakEventListener;

            private PropertyChangedEventManagerProxy()
            {
                _notifyPropertyChangedProxy = new NotifyPropertyChangedProxy();
                _weakEventListener = new WeakListenerStub();

                PropertyChangedEventManager.AddListener(_notifyPropertyChangedProxy, _weakEventListener, string.Empty);
            }

            public void RaisePropertyChanged(object sender, string propertyName)
            {
                _notifyPropertyChangedProxy.Raise(sender, new PropertyChangedEventArgs(propertyName));
            }

            private static PropertyChangedEventManagerProxy _instance;
            public static PropertyChangedEventManagerProxy Instance { get { return _instance ?? (_instance = new PropertyChangedEventManagerProxy()); } }

            private class NotifyPropertyChangedProxy : INotifyPropertyChanged
            {
                public event PropertyChangedEventHandler PropertyChanged = delegate { };

                public void Raise(object sender, PropertyChangedEventArgs e)
                {
                    PropertyChanged(sender, e);
                }
            }

            private class WeakListenerStub : IWeakEventListener
            {
                public bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e) { return false; }
            }
        }
    }
}

{'fraction_non_alphanumeric': 0.09373853042648463, 'fraction_numerical': 0.00029362108199368716, 'mean_word_length': 2.242265587815326, 'pattern_counts': {'":': 0, '<': 119, '<?xml version=': 0, '>': 119, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5081214', 'n_tokens_mistral': 3216, 'n_tokens_neox': 3082, 'n_words': 905}