/// <summary> /// Indexer /// </summary> /// <param name="key"></param> /// <returns></returns> public object this[string key] { get { DataObject obj = this.FindRecursive(key); if (obj is null) { throw new KeyNotFoundException(); } return(obj.GetValue()); } set { DataObject obj = this.FindRecursive(key); if (obj is null) { throw new KeyNotFoundException(); } obj.SetValue(value); } }
/// <summary> /// Takes in 2 <see cref="IDataContainer"/> returns new instance of <see cref="IDataContainer"/> /// which containes properties which are both in LHS and RHS, the values will be from LHS /// </summary> /// <param name="lhs"></param> /// <param name="rhs"></param> /// <returns>LHS ^ RHS</returns> public static IDataContainer Intersect(this IDataContainer lhs, IDataContainer rhs) { IDataContainer intersect = lhs is IPropertyContainer ? (IDataContainer) new PropertyContainer() : new DataContainer(); intersect.Name = lhs.Name; var lhsKeys = lhs.GetKeys(); var rhsKeys = rhs.GetKeys(); var intersectKeys = lhsKeys.Intersect(rhsKeys); foreach (var key in intersectKeys) { DataObject first = lhs.Find(key); // in case of nested IDataContainer if (first.GetValue() is IDataContainer dc) { var second = rhs.Find(first.Name).GetValue() as IDataContainer; if (dc.IsIdentical(second) == false) { first.SetValue(dc.Intersect(second)); } } intersect.Add(first); } return(intersect); }
/// <summary> /// Add new properties from second to first, if they already exist, keep the values. /// Same as <see cref="Union(IDataContainer, IDataContainer)"/> but does operation inplace instead of returning new intance; /// </summary> /// <param name="lhs"></param> /// <param name="rhs"></param> public static bool Merge(this IDataContainer lhs, IDataContainer rhs) { bool result = false; bool innerResult = false; foreach (var data in rhs) { if (lhs.ContainsData(data.Name) == false) { lhs.Add(data); result = true; } else { DataObject lhsData = lhs.Find(data.Name); // No need to update value, but update the details if (data is PropertyObject propRhs && lhsData is PropertyObject propLhs) { result = propLhs.DisplayName != propRhs.DisplayName || propLhs.Category != propRhs.Category || propLhs.Description != propRhs.Description; propLhs.DisplayName = propRhs.DisplayName; propLhs.Category = propRhs.Category; propLhs.Description = propRhs.Description; } if (lhsData.GetValue() is IDataContainer dc) { IDataContainer rhsDC = data.GetValue() as IDataContainer; bool temp = dc.Merge(rhsDC); innerResult = temp || innerResult; } } } return(result || innerResult); }
/// <summary> /// Reload values from file again /// Doesn't need new properties if added, only updates existing ones /// </summary> /// <param name="dc"></param> public static void Refresh(this IDataContainer dc, IDataContainer changed) { foreach (var data in changed) { object value = data.GetValue(); if (value is IDataContainer changedChild) { DataObject dcChild = dc.Find(data.Name); if (dcChild != null) { IDataContainer dcChildValue = dcChild.GetValue() as IDataContainer; dcChildValue.Refresh(changedChild); } } else { dc.SetValue(data.Name, value); } } }
/// <summary> /// Implementation for <see cref="PropertyDescriptor.GetValue(object)"/> /// </summary> /// <param name="component"></param> /// <returns></returns> public override object GetValue(object component) { return(DataObject is IEditorValueProvider icvp ? icvp.GetEditorValue() : DataObject.GetValue()); }