Files
SourceCode/PROMS/VEPROMS.CSLA.Library/Format/vlnFormat.cs
T

674 lines
25 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.ComponentModel;
namespace VEPROMS.CSLA.Library
{
#region vlnFormatDocument
public class vlnFormatDocument:XmlDocument
{
private static XmlElement mydocele;
public vlnFormatDocument(IFormatOrFormatInfo myFormat)
{
MyFormat = myFormat;
LoadXml(MyFormat.Data);
mydocele = DocumentElement;
}
public IFormatOrFormatInfo MyFormat { get; set; }
public static XmlNode LookupSingleNode(XmlNode xmlNode, string path)
{
if (xmlNode == null) return null;
XmlNode xn = xmlNode.SelectSingleNode(path);
if (xmlNode.Name == "Box") return xn; // if box, don't do inheritance.
if (xmlNode.Name == "DocStyle") return xn;
//C2025-023 - Electronic Procedures - Modifications to PROMS
if (xmlNode.Name == "EPField") return xn; // if Electronic Procedure Field, don't do inheritance.
if (xmlNode.Name == "StructureStyle")
{
Volian.Base.Library.DebugText.WriteLine("vlnFormatDocument:LookupSingleNode:StructureStyle - shouldn't get to this line of code.\r\nPath = {0}", path);
return xn; // User Format (sub format) - shouldn't? inherit? -need to check
}
if (xn != null) return xn;
//if (path.Contains("Font")) Console.WriteLine("vlnFormatDocument.LookupSingleNode {0},{1}", xmlNode.Name == "Step" ? "Step." + xmlNode.Attributes["Type"].Value : xmlNode.Name, path);
if (xmlNode.Name == "Step") xn = LookupSingleStepNode(xmlNode, path); // Check for Step Inheritance
if (xmlNode.ParentNode.Name == "Step")
xn = LookupSingleStepNode(xmlNode.ParentNode, xmlNode.Name + "/" + path); // Check for Step Inheritance
if (xn != null) return xn;
if (path.StartsWith("Font")) return LookupSingleFontNode(xmlNode, path); // Then do Font Inheritance
return InheritLookup(xmlNode, path, false);
}
public static XmlNode LookupSingleFontNode(XmlNode xmlNode, string path)
{
if (xmlNode == null) return null;
XmlNode tmpNode = xmlNode;
XmlNode xn = xmlNode.SelectSingleNode(path);
// RHM 2008-12-15 - Added logic to keep looking if a blank attribute is found
while (xn == null || (xn is XmlAttribute && (xn as XmlAttribute).Value == ""))//Walk-up the format tree to find a font node
{
// if the font is not specified in the PageStyle (PageList), then see if oneis set in the DocStyle (default for that section)
//
if (xmlNode.Name == "PageStyle")
{
string psIdx = (xmlNode.Attributes.GetNamedItem("Index") as XmlAttribute).Value;
XmlNode docStyle = xmlNode.OwnerDocument.SelectSingleNode(string.Format("//DocStyle[@PageStyle='{0}']",psIdx));
xn = docStyle.SelectSingleNode(path);
if (xn != null) return xn;
// could not find a font in the DocStyle, so use the format default
return LookupSingleNode(tmpNode.OwnerDocument.DocumentElement, "/PlantFormat/FormatData/" + path);
}
if (xmlNode.NodeType == XmlNodeType.Document)
{
//if (path.Contains("Font")) Console.WriteLine("vlnFormatDocument.LookupSingleFontNode {0},{1}", tmpNode.Name == "Step" ? "Step." + tmpNode.Attributes["Type"].Value : tmpNode.Name, path);
return LookupSingleNode(tmpNode.OwnerDocument.DocumentElement, "/PlantFormat/FormatData/" + path);
}
xmlNode = xmlNode.ParentNode;
xn = xmlNode.SelectSingleNode(path);
}
return xn;
}
public static XmlNode LookupSingleStepNode(XmlNode xmlNode, string path)
{
if (xmlNode == null) return null;
XmlNode xn = xmlNode.SelectSingleNode(path);
XmlNode tmpNode2 = xmlNode;
while (xn == null) //Walk-up the format tree to find a step node
{
//if (path.Contains("Font")) Console.WriteLine("vlnFormatDocument.LookupSingleStepNode -> Loop {0},{1}", xmlNode.Name == "Step" ? "Step." + xmlNode.Attributes["Type"].Value : xmlNode.Name, path);
// RHM 20090831 Try doing a lookup of the parent. If no parent, go back to the original and do an inheritance lookup
XmlAttribute attr = xmlNode.Attributes["ParentType"];
if (attr == null || attr.Value == string.Empty) // Cannot find ParentType so do an InheritanceLookup
return InheritLookup(tmpNode2, path, true);
xmlNode = xmlNode.ParentNode.SelectSingleNode(string.Format("Step[@Type='{0}']", xmlNode.Attributes["ParentType"].InnerText));
xn = xmlNode.SelectSingleNode(path);
}
return xn;
}
public static XmlNodeList LookupNodes(XmlNode xmlNode, string path)
{
if (xmlNode == null) return null;
XmlNodeList xl = xmlNode.SelectNodes(path);
if (xl == null||xl.Count==0) xl = InheritLookupNodes(xmlNode, path);
if (xl == null) return null;
return xl;
}
public static string Lookup(XmlNode xmlNode, string path)
{
XmlNode xn = LookupSingleNode(xmlNode, path);
return xn?.InnerText;
}
public static T EnumLookup<T>(XmlNode xmlNode, string path)
{
string str = Lookup(xmlNode,path);
return str == null ? default : (T)Enum.Parse(typeof(T), str);
}
public static int? IntLookup(XmlNode xmlNode, string path)
{
string str = Lookup(xmlNode, path);
return str == null ? null : (int?)int.Parse(str);
}
public static int SiblingCount(XmlNode xmlNode)
{
int retval = 0;
string nodeName = xmlNode.Name;
for (XmlNode xn = xmlNode; xn != null; xn = xn.PreviousSibling)
{
if (xn.Name == nodeName) retval++;
}
return retval;
}
public static string Path(XmlNode xmlNode)
{
// Walk the path
string parentPath = xmlNode.ParentNode == xmlNode.OwnerDocument ? "" : Path(xmlNode.ParentNode);
// Count Siblings with the Same Name
int sibCount = SiblingCount(xmlNode);
return string.Format("{0}/{1}[{2}]", parentPath, xmlNode.Name, sibCount);
}
//B2026-077 – Update Format inheritance to use index id instead of position/order.
public static string PathByIndex(XmlNode xmlNode)
{
if (xmlNode.Name == "TransTypes" || xmlNode.Name == "Step")
{
string parentPath = xmlNode.ParentNode == xmlNode.OwnerDocument ? "" : Path(xmlNode.ParentNode);
string Indx = xmlNode.Attributes["Index"].Value;
return $@"{parentPath}/{xmlNode.Name}[@Index='{Indx}']";
}
else
{
return Path(xmlNode);
}
}
public static XmlNode InheritLookup(XmlNode xmlNode, string path, bool stepLookup)
{
//stepLookup = false; // 8/2 change for inheritance
if (xmlNode == null) return null;// No path to match
string xPath = PathByIndex(xmlNode);// Build xPath from xmlNode
vlnFormatDocument fd = (vlnFormatDocument)xmlNode.OwnerDocument;//First Get the vlnFormatDocument - This also ties it to a FormatInfo object
while(fd.MyFormat.MyIParent != null)
{
fd = fd.MyFormat.MyIParent.PlantFormat.XmlDoc;// Get the parents vlnFormatDocument
if (fd != null)
{
XmlNode xp;
if (path.StartsWith("/")) xp = fd.DocumentElement;
else xp = fd.SelectSingleNode(xPath);// Get the related node
if (xp != null)
{
XmlNode xn;
if (stepLookup)
{
//if (path.Contains("Font")) Console.WriteLine("vlnFormatItem.SelectSingleNode {0},{1}", xp.Name == "Step" ? "Step." + xp.Attributes["Type"].Value : xp.Name, path);
xn = LookupSingleStepNode(xp, path);
}
else
xn = xp.SelectSingleNode(path);
if(xn != null) return xn;
}
}
}
return null;
}
public static XmlNodeList InheritLookupNodes(XmlNode xmlNode, string path)
{
if (xmlNode == null) return null;// No path to match
string xPath = Path(xmlNode);// Build xPath from xmlNode
vlnFormatDocument fd = (vlnFormatDocument)xmlNode.OwnerDocument;//First Get the vlnFormatDocument - This also ties it to a FormatInfo object
while (fd.MyFormat.MyIParent != null)
{
fd = fd.MyFormat.MyIParent.PlantFormat.XmlDoc;// Get the parents vlnFormatDocument
if (fd != null)
{
XmlNode xp = fd.SelectSingleNode(xPath);// Get the related node
if (xp != null)
{
XmlNodeList xl = xp.SelectNodes(path);
if (xl != null && xl.Count > 0)
return xl;
}
}
}
return null;
}
}
#endregion
#region vlnFormatItem
[TypeConverter(typeof(ExpandableObjectConverter))]
public class vlnFormatItem
{
public vlnFormatItem(XmlNode xmlNode) => XmlNode = xmlNode;
public vlnFormatItem() { }
internal XmlNode XmlNode { get; set; }
private IFormatOrFormatInfo _MyFormat;
public IFormatOrFormatInfo MyFormat
{
get
{
if (_MyFormat == null)
{
if (XmlNode.OwnerDocument is vlnFormatDocument doc)
_MyFormat = doc.MyFormat;
}
return _MyFormat;
}
}
public IFormatOrFormatInfo MyParentFormat => MyFormat.MyIParent;
public virtual string GetPDDisplayName() => ToString();
public virtual string GetPDName() => ToString();
public virtual string GetPDDescription() => ToString();
public virtual string GetPDCategory() => ToString();
public XmlNodeList SelectNodes(string path) => vlnFormatDocument.LookupNodes(XmlNode, path);
public XmlNode SelectSingleNode(string path)
{
//if(path.Contains("Font")) Console.WriteLine("vlnFormatItem.SelectSingleNode {0},{1}", _XmlNode.Name == "Step" ? "Step." + _XmlNode.Attributes["Type"].Value : _XmlNode.Name, path);
return vlnFormatDocument.LookupSingleNode(XmlNode, path);
}
public XmlNode SelectSingleFontNode(string path) => vlnFormatDocument.LookupSingleFontNode(XmlNode, path);
public string Lookup(string path) => vlnFormatDocument.Lookup(XmlNode, path);
public string Lookup(string path, ref string local) => local ?? (local = Lookup(path));
public int? IntLookup(string path) => vlnFormatDocument.IntLookup(XmlNode, path);
public int? IntLookup(string path, ref int? local) => local != null ? local : local = IntLookup(path);
public T EnumLookup<T>(string path) => vlnFormatDocument.EnumLookup<T>(XmlNode, path);
public bool LazyLoad(ref LazyLoad<bool> ll, string xPath)
{
if (ll == null)
{
XmlNode xn = SelectSingleNode(xPath);
ll = new LazyLoad<bool>(RetrieveBool(xn));
}
return ll.Value;
}
protected static bool RetrieveBool(XmlNode xn) => xn != null && xn.InnerText.ToUpper() == "TRUE";
// a LazyLoad that allows you to pass in the default setting
public bool LazyLoad(ref LazyLoad<bool> ll, string xPath, bool defaultReturn)
{
if (ll == null)
{
XmlNode xn = SelectSingleNode(xPath);
ll = new LazyLoad<bool>(RetrieveBool(xn, defaultReturn));
}
return ll.Value;
}
// if nothing is set for this node, then use the passed in default value
protected static bool RetrieveBool(XmlNode xn, bool defaultReturn) => (xn != null) ? xn.InnerText.ToUpper() == "TRUE" : defaultReturn;
public string LazyLoad(ref LazyLoad<string> ll, string xPath)
{
if (ll == null)
{
XmlNode xn = SelectSingleNode(xPath);
ll = new LazyLoad<string>(RetrieveString(xn));
}
return ll.Value;
}
protected static string RetrieveString(XmlNode xn) => xn?.InnerText;
public string MyPath
{
get
{
StringBuilder sb = new StringBuilder();
XmlNode node = XmlNode;
string prefix = "";
while (node != null)
{
sb.Insert(0, node.Name + prefix);
prefix = "/";
node = node.ParentNode;
}
return sb.ToString();
}
}
public int? LazyLoad(ref LazyLoad<int?> ll, string xPath)
{
if (ll == null)
{
XmlNode xn = SelectSingleNode(xPath);
ll = new LazyLoad<int?>(RetrieveInt(xPath, xn));
}
return ll.Value;
}
public float? LazyLoad(ref LazyLoad<float?> ll, string xPath)
{
if (ll == null)
{
XmlNode xn = SelectSingleNode(xPath);
ll = new LazyLoad<float?>(RetrieveFloat(xPath, xn));
}
return ll.Value;
}
protected int? RetrieveInt(string xPath, XmlNode xn)
{
int? value = null;
if (xn != null)
{
if (!int.TryParse(xn.InnerText, out int iValue))
{
if (xn.InnerText == "") return null;
Console.WriteLine(string.Format("'{0}'\r\n'{1}'\r\n'{2}' could not be converted to int?", MyFormat.FullName, MyPath + "/" + xPath, xn.InnerText));
throw new Exception(string.Format("{0} = '{1}' could not be converted to int?", xPath, xn.InnerText));
}
value = iValue;
}
return value;
}
protected float? RetrieveFloat(string xPath, XmlNode xn)
{
float? value = null;
if (xn != null)
{
if (!float.TryParse(xn.InnerText, out float fValue))
{
Console.WriteLine(string.Format("'{0}'\r\n'{1}'\r\n'{2}' could not be converted to float?", MyFormat.FullName, MyPath + "/" + xPath, xn.InnerText));
throw new Exception(string.Format("{0} = '{1}' could not be converted to float?", xPath, xn.InnerText));
}
value = fValue;
}
return value;
}
public Nullable<T> LazyLoad<T>(ref LazyLoad<Nullable<T>> ll, string xPath)
where T:struct
{
if (ll == null)
{
XmlNode xn = SelectSingleNode(xPath);
if (xn == null)
ll = new LazyLoad<T?>(null);
else if (xn.Value == "")// No value specified - Use zero value if it is defined - GetName returns a null if it is not defined
ll = new LazyLoad<Nullable<T>>(Enum.GetName(typeof(T), 0) != null ? (Nullable<T>) Enum.Parse(typeof(T), "0") : null);
else
try
{
ll = new LazyLoad<Nullable<T>>((Nullable<T>)Enum.Parse(typeof(T), xn.InnerText));
}
catch (Exception ex)
{
Console.WriteLine("{0} - '{1}'", ex.Message, xn.InnerText);
ll = new LazyLoad<T?>(null);
}
}
return ll.Value;
}
}
#endregion
#region IVlnIndexedFormatItem
public partial interface IVlnIndexedFormatItem
{
int? Index { get; }
}
#endregion
#region IVlnNamedFormatItem
public partial interface IVlnNamedFormatItem
{
string Name { get; }
bool Inherited { get; }
}
#endregion
#region LazyLoad
public class LazyLoad<T>
{
public LazyLoad(T value) => Value = value;
public T Value { get; set; }
}
#endregion
#region vlnFormatList, new()
public class vlnFormatList<T> : List<T>, ICustomTypeDescriptor
where T : vlnFormatItem, new()
{
private XmlNodeList _XmlNodeList=null;
internal XmlNodeList XmlNodeList
{
get { return _XmlNodeList; }
set
{
_XmlNodeList = value;
foreach (XmlNode xn in _XmlNodeList)
{
T tt = new T
{
XmlNode = xn
};
Add(tt);
}
}
}
public vlnFormatList(XmlNodeList xmlNodeList)
{
if (xmlNodeList == null) return;
XmlNodeList = xmlNodeList;
}
public vlnFormatList()
{
}
private IFormatOrFormatInfo _MyFormat;
public IFormatOrFormatInfo MyFormat
{
get
{
if (_MyFormat == null)
{
XmlNode node = _XmlNodeList[0]; // Get the first node in a list
vlnFormatDocument doc = null;
if (node != null)
doc = node.OwnerDocument as vlnFormatDocument; // Get the owner document as a vlnFormatDocument
if (doc != null)
_MyFormat = doc.MyFormat; // Get the Format associated with the vlnFormatDocument
}
return _MyFormat;
}
set
{
_MyFormat = value;
}
}
#region ICustomTypeDescriptor
public string GetClassName() => TypeDescriptor.GetClassName(this, true);
public AttributeCollection GetAttributes() => TypeDescriptor.GetAttributes(this, true);
public string GetComponentName() => TypeDescriptor.GetComponentName(this, true);
public TypeConverter GetConverter() => TypeDescriptor.GetConverter(this, true);
public EventDescriptor GetDefaultEvent() => TypeDescriptor.GetDefaultEvent(this, true);
public PropertyDescriptor GetDefaultProperty() => TypeDescriptor.GetDefaultProperty(this, true);
public object GetEditor(Type editorBaseType) => TypeDescriptor.GetEditor(this, editorBaseType, true);
public EventDescriptorCollection GetEvents(Attribute[] attributes) => TypeDescriptor.GetEvents(this, attributes, true);
public EventDescriptorCollection GetEvents() => TypeDescriptor.GetEvents(this, true);
public object GetPropertyOwner(PropertyDescriptor pd) => this;
public PropertyDescriptorCollection GetProperties(Attribute[] attributes) => GetProperties();
public virtual PropertyDescriptorCollection GetProperties()
{
// Create a collection object to hold property descriptors
PropertyDescriptorCollection pds = new PropertyDescriptorCollection(null);
// Iterate the list
for (int i = 0; i < Count; i++)
{
// Create a property descriptor for the item and add to the property descriptor collection
pds.Add(new vlnPropertyDescriptor<vlnFormatList<T>, T>(this, i));
}
// return the property descriptor collection
return pds;
}
#endregion
}
#endregion
#region vlnIndexedFormatList
public class vlnIndexedFormatList<T> : vlnFormatList<T>, ICustomTypeDescriptor
where T : vlnFormatItem,IVlnIndexedFormatItem, new()
{
public vlnIndexedFormatList(XmlNodeList xmlNodeList, IFormatOrFormatInfo myFormat) : base(xmlNodeList) => MyFormat = myFormat;
public vlnIndexedFormatList() : base() { }
public virtual vlnIndexedFormatList<T> InheritedList => null;
public new T this[int index]
{
get
{
foreach (T tmp in this)
{
if (tmp.Index == index)
return tmp;
}
vlnIndexedFormatList<T> ttlParent = InheritedList; //Check Inherited Value
if (ttlParent != null)
return ttlParent[index];
return null;
}
}
public int MaxIndex
{
get
{
int max = base.Count;
foreach (T tmp in this)
{
if (tmp.Index >= max)
max = ((int)tmp.Index) + 1;
}
vlnIndexedFormatList<T> parent = InheritedList; //Check Inherited Value
if (parent != null)
{
int max2 = parent.MaxIndex;
if (max2 > max)
return max2;
}
return max;
}
}
public int MaxIndexNoInherit
{
get
{
int max = base.Count;
foreach (T tmp in this)
{
if (tmp.Index >= max)
max = ((int)tmp.Index) + 1;
}
return max;
}
}
#region ICustomTypeDescriptor
public new string GetClassName() => TypeDescriptor.GetClassName(this, true);
public new AttributeCollection GetAttributes() => TypeDescriptor.GetAttributes(this, true);
public new string GetComponentName() => TypeDescriptor.GetComponentName(this, true);
public new TypeConverter GetConverter() => TypeDescriptor.GetConverter(this, true);
public new EventDescriptor GetDefaultEvent() => TypeDescriptor.GetDefaultEvent(this, true);
public new PropertyDescriptor GetDefaultProperty() => TypeDescriptor.GetDefaultProperty(this, true);
public new object GetEditor(Type editorBaseType) => TypeDescriptor.GetEditor(this, editorBaseType, true);
public new EventDescriptorCollection GetEvents(Attribute[] attributes)
{ return TypeDescriptor.GetEvents(this, attributes, true); }
public new EventDescriptorCollection GetEvents() => TypeDescriptor.GetEvents(this, true);
public new object GetPropertyOwner(PropertyDescriptor pd) => this;
public new PropertyDescriptorCollection GetProperties(Attribute[] attributes) => GetProperties();
public new virtual PropertyDescriptorCollection GetProperties()
{
// Create a collection object to hold property descriptors
PropertyDescriptorCollection pds = new PropertyDescriptorCollection(null);
// Iterate the list
for (int i = 0; i < Count; i++)
{
// Create a property descriptor for the item and add to the property descriptor collection
pds.Add(new vlnPropertyDescriptor<vlnFormatList<T>, T>(this, i));
}
// return the property descriptor collection
return pds;
}
#endregion
}
#endregion
#region vlnNamedFormatList
public class vlnNamedFormatList<T> : vlnFormatList<T>, ICustomTypeDescriptor
where T : vlnFormatItem, IVlnNamedFormatItem, new()
{
public vlnNamedFormatList(XmlNodeList xmlNodeList, IFormatOrFormatInfo myFormat)
: base(xmlNodeList) => MyFormat = myFormat;
public vlnNamedFormatList() : base() { }
public virtual vlnNamedFormatList<T> InheritedList => null;
public T this[string name]
{
get
{
foreach (T tmp in this)
{
if (tmp.Name == name)
return tmp;
}
vlnNamedFormatList<T> ttlParent = InheritedList; //Check Inherited Value
if (ttlParent != null)
return ttlParent[name];
return null;
}
}
public new T this[int index]
{
get
{
if(base.Count > index)
return base[index];
vlnNamedFormatList<T> ttlParent = InheritedList; //Check Inherited Value
if (ttlParent != null)
return ttlParent[index];
return null;
}
}
public new int Count => base.Count;
#region ICustomTypeDescriptor
public new string GetClassName() => TypeDescriptor.GetClassName(this, true);
public new AttributeCollection GetAttributes() => TypeDescriptor.GetAttributes(this, true);
public new string GetComponentName() => TypeDescriptor.GetComponentName(this, true);
public new TypeConverter GetConverter() => TypeDescriptor.GetConverter(this, true);
public new EventDescriptor GetDefaultEvent() => TypeDescriptor.GetDefaultEvent(this, true);
public new PropertyDescriptor GetDefaultProperty() => TypeDescriptor.GetDefaultProperty(this, true);
public new object GetEditor(Type editorBaseType) => TypeDescriptor.GetEditor(this, editorBaseType, true);
public new EventDescriptorCollection GetEvents(Attribute[] attributes) => TypeDescriptor.GetEvents(this, attributes, true);
public new EventDescriptorCollection GetEvents() => TypeDescriptor.GetEvents(this, true);
public new object GetPropertyOwner(PropertyDescriptor pd) => this;
public new PropertyDescriptorCollection GetProperties(Attribute[] attributes) => GetProperties();
public new virtual PropertyDescriptorCollection GetProperties()
{
// Create a collection object to hold property descriptors
PropertyDescriptorCollection pds = new PropertyDescriptorCollection(null);
// Iterate the list
for (int i = 0; i < Count; i++)
{
// Create a property descriptor for the item and add to the property descriptor collection
pds.Add(new vlnPropertyDescriptor<vlnFormatList<T>, T>(this, i));
}
// return the property descriptor collection
return pds;
}
#endregion
}
#endregion
#region vlnListConverter
internal class vlnListConverter<T, C> : ExpandableObjectConverter
where T : vlnFormatList<C>
where C : vlnFormatItem, new()
{
private string Plural(string name)
{
if (name.EndsWith("y")) return $"{name.Substring(0, name.Length - 1)}ies";
if (name.EndsWith("ss")) return $"{name}es";
else return $"{name}s";
}
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destType)
{
if (destType == typeof(string) && value is T vart)
{
// Return department and department role separated by comma.
return $"{vart.Count} {(vart.Count == 1 ? typeof(C).Name : Plural(typeof(C).Name))}";
}
return base.ConvertTo(context, culture, value, destType);
}
}
#endregion
#region vlnIndexedListConverter
internal class vlnIndexedListConverter<T, C> : ExpandableObjectConverter
where T : vlnIndexedFormatList<C>
where C : vlnFormatItem,IVlnIndexedFormatItem, new()
{
private string Plural(string name)
{
if (name.EndsWith("y")) return $"{name.Substring(0, name.Length - 1)}ies";
if (name.EndsWith("ss")) return $"{name}es";
return name.EndsWith("x") ? $"{name}es" : $"{name}s";
}
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destType)
{
if (destType == typeof(string) && value is T vart)
{
// Return department and department role separated by comma.
return $"{vart.MaxIndex} {(vart.MaxIndex == 1 ? typeof(C).Name : Plural(typeof(C).Name))}";
}
return base.ConvertTo(context, culture, value, destType);
}
}
#endregion
#region vlnPropertyDescriptor
public class vlnPropertyDescriptor<T, C> : PropertyDescriptor
where T : vlnFormatList<C>
where C : vlnFormatItem, new()
{
protected C _Item = null;
public vlnPropertyDescriptor(T itemList, int index)
: base("#" + index.ToString(), null) => _Item = itemList[index];
public override bool CanResetValue(object component) => true;
public override Type ComponentType => _Item.GetType();
public override object GetValue(object component) => _Item;
public override bool IsReadOnly => true;
public override Type PropertyType => _Item.GetType();
public override void ResetValue(object component)
{ ;}
public override bool ShouldSerializeValue(object component) => true;
public override void SetValue(object component, object value)
{ /*_Item = value*/;}
public override string DisplayName => _Item.GetPDDisplayName();
public override string Description => _Item.GetPDDescription();
public override string Name => _Item.GetPDName();
public override string Category => _Item.GetPDCategory();
} // Class
#endregion
}