Code development platform for open source projects from the European Union institutions

Skip to content
Snippets Groups Projects
BackingStorage.cs 3.86 KiB
Newer Older
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using TUGraz.VectoCommon.Utils;

namespace VECTO3GUI2020.ViewModel.Implementation.Common
{
	public class BackingStorage<T> : ObservableObject 
		where T : INotifyPropertyChanged
	{
Harald MARTINI's avatar
Harald MARTINI committed
		private delegate object GetterDelegate();
		private IReadOnlyCollection<string> _observedProperties;
		private T _observedObject;

Harald MARTINI's avatar
Harald MARTINI committed
		private Dictionary<string, MethodInfo> _getterMethodInfos = new Dictionary<string, MethodInfo>();
		private Dictionary<string, Type> _propertyTypesMap = new Dictionary<string, Type>();
		private IDictionary<string, IEqualityComparer> _equalityComparers = new Dictionary<string, IEqualityComparer>();

		private IDictionary<string, object> _savedValues = null;
		private IDictionary<string, object> _unsavedChanges = new Dictionary<string, object>();
		private IDictionary<string, object> _currentValues = new Dictionary<string, object>();

		public BackingStorage(T observedObject, params string[] observedProperties)
		{
			_observedProperties = new HashSet<string>(observedProperties);
			_observedObject = observedObject;
			observedObject.PropertyChanged += OnObservedPropertyChanged;
Harald MARTINI's avatar
Harald MARTINI committed
			var list = new List<object>() {
				true,
				"Hi"
			};
			get => (_savedValues == null) || (_unsavedChanges.Count != 0);
		}

		private void ResetUnsavedChanges()
		{
			_unsavedChanges.Clear();
			OnPropertyChanged(nameof(UnsavedChanges));
			_savedValues = new ReadOnlyDictionary<string, object>(new Dictionary<string, object>(_currentValues));
			ResetUnsavedChanges();
		}

		private void OnObservedPropertyChanged(object sender, PropertyChangedEventArgs e)
		{
			var propertyName = e.PropertyName;
			if (!_observedProperties.Contains(propertyName)) {
				return;
			}

Harald MARTINI's avatar
Harald MARTINI committed
			if (!_getterMethodInfos.ContainsKey(propertyName)) {
				StorePropertyInfo(propertyName);
			}

			UpdateValue(propertyName);
		}

		private void UpdateValue(string propertyName)
		{
Harald MARTINI's avatar
Harald MARTINI committed

            //var newValue = ((GetterDelegate)_getterDelegatesMap[propertyName])();
			var newValue = _getterMethodInfos[propertyName].Invoke(_observedObject, new object[] { });
            _currentValues[propertyName] = newValue;
			if (ValueHasChanged(newValue, propertyName)) {
				_unsavedChanges[propertyName] = newValue;
			} else {
				_unsavedChanges.Remove(propertyName);
			}
			OnPropertyChanged(nameof(UnsavedChanges));
		}

		private bool ValueHasChanged(object newValue, string propertyName)
		{
			if (_savedValues == null
				|| !_savedValues.ContainsKey(propertyName)) {
				return true;
			}

			var savedValue = _savedValues[propertyName];

			if (_equalityComparers.ContainsKey(propertyName)) {
				var equalityComparer = _equalityComparers[propertyName];
				return !equalityComparer.Equals(newValue, savedValue);
			} else {
				return newValue == savedValue;
			}
		}

		private void StorePropertyInfo(string propertyName)
		{
			var propInfo = _observedObject.GetType().GetProperty(propertyName);


			var propertyType = propInfo.PropertyType;
			_propertyTypesMap[propertyName] = propInfo.PropertyType;

			try {
				_equalityComparers[propertyName] = CreateEqualityComparer(propertyType);
			} catch (Exception ex) {
				// TODO;
			}
			


			var getMethod = propInfo.GetGetMethod();
Harald MARTINI's avatar
Harald MARTINI committed
			
			
			//var getterDelegate = getMethod.CreateDelegate(typeof(Delegate), _observedObject);
			_getterMethodInfos[propertyName] = getMethod;


		}

		private static IEqualityComparer CreateEqualityComparer(Type type)
		{

			Type myGeneric = typeof(EqualityComparer<>);
			Type constructedClass = myGeneric.MakeGenericType(type);
			return (IEqualityComparer)constructedClass
				.GetProperty(nameof(EqualityComparer<T>.Default), BindingFlags.Static | BindingFlags.Public)
				.GetValue(null);