internal void DumpFieldInfo(IFwMetaDataCache mdc) { if (this.Depth == 0) { Debug.WriteLine(""); } for (int i = 0; i < this.Depth; ++i) { Debug.Write(" "); } if (Source != 0) { Debug.WriteLine("[" + this.Depth + "]info.Source = " + this.Source + " = " + GetFancyFieldName(this.Source, mdc)); } else { Debug.WriteLine("Root (target) class: " + mdc.GetClassName(m_targetClass)); } for (int i = 0; i < this.AtomicFields.Count; ++i) { for (int j = 0; j < this.Depth; ++j) { Debug.Write(" "); } Debug.WriteLine(" Atomic[" + i + "] flid = " + this.AtomicFields[i].flid + "(" + GetFancyFieldName(this.AtomicFields[i].flid, mdc) + "); ws = " + this.AtomicFields[i].ws); } for (int i = 0; i < this.SeqFields.Count; ++i) { this.SeqFields[i].DumpFieldInfo(mdc); } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Initializes a new instance of the <see cref="T:FwModelBrowser"/> class. /// </summary> /// ------------------------------------------------------------------------------------ public FwModelBrowser() { // // Required for Windows Form Designer support // InitializeComponent(); #if USINGCPP m_ode = OleDbEncapClass.Create(); m_ode.Init(SystemInformation.ComputerName + "\\SILFW", "TestLangProj", null, FwKernelLib.OdeLockTimeoutMode.koltReturnError, (int)FwKernelLib.OdeLockTimeoutValue.koltvFwDefault); m_mdc = FwMetaDataCacheClass.Create(); m_mdc.Init(m_ode); #else string modelDir = DirectoryFinder.FwSourceDirectory; modelDir = modelDir.Substring(0, modelDir.LastIndexOf('\\')); modelDir = Path.Combine(modelDir, @"Output\XMI"); m_mdc = MetaDataCache.CreateMetaDataCache(Path.Combine(modelDir, "xmi2cellar3.xml")); #endif uint clid = 0; string classname = m_mdc.GetClassName(clid); m_tvClasses.SuspendLayout(); AddNode(m_tvClasses.Nodes, classname, clid); m_tvClasses.Nodes[0].Expand(); m_tvClasses.ResumeLayout(false); }
/// <summary> /// /// </summary> /// <param name="mdc"></param> /// <param name="tbl"></param> /// <param name="clsId"></param> /// <param name="titleStr">*{dstClass}* if couldn't find result.</param> /// <returns>true if we found an alternate form. false if titleStr is null or in *{ClassName}* format.</returns> public static bool TryFindPluralFormFromClassId(IFwMetaDataCache mdc, StringTable tbl, int clsId, out string titleStr) { titleStr = null; if (clsId != 0) { string className = mdc.GetClassName(clsId); return TryFindString(tbl, "AlternativeTitles", String.Format("{0}-Plural", className), out titleStr); } return false; }
bool m_fGotFocus = false; // True if we have focus. public TypeAheadSupportVc(int tag, LcmCache cache) { m_tag = tag; IFwMetaDataCache mdc = cache.DomainDataByFlid.MetaDataCache; m_clid = mdc.GetOwnClsId(m_tag); m_className = mdc.GetClassName(m_clid); m_fieldName = mdc.GetFieldName(m_tag); m_type = (CellarPropertyType)(mdc.GetFieldType(m_tag) & (int)CellarPropertyTypeFilter.VirtualMask); m_sda = cache.DomainDataByFlid; Cache = cache; }
bool m_fGotFocus = false; // True if we have focus. public TypeAheadSupportVc(int tag, FdoCache cache) { m_tag = tag; IFwMetaDataCache mdc = cache.MetaDataCacheAccessor; m_clid = mdc.GetOwnClsId((uint)m_tag); m_className = mdc.GetClassName(m_clid); m_fieldName = mdc.GetFieldName((uint)m_tag); m_type = mdc.GetFieldType((uint)m_tag); m_type = m_type & 0x1f; // strip off virtual bit. m_sda = cache.MainCacheAccessor; m_cache = cache; CreateVirtualProperties(); }
private void AddSubNodes(TreeNodeCollection parentNodeCollection, uint superClassClid) { int directSubclassCount; m_mdc.GetDirectSubclasses(superClassClid, 0, out directSubclassCount, null); uint[] uIds; using (ArrayPtr clids = MarshalEx.ArrayToNative(directSubclassCount, typeof(uint))) { m_mdc.GetDirectSubclasses(superClassClid, directSubclassCount, out directSubclassCount, clids); uIds = (uint[])MarshalEx.NativeToArray(clids, directSubclassCount, typeof(uint)); } SortedList <string, uint> list = new SortedList <string, uint>(uIds.Length); foreach (uint subclassClid in uIds) { string classname = m_mdc.GetClassName(subclassClid); list.Add(classname, subclassClid); } foreach (KeyValuePair <string, uint> kvp in list) { AddNode(parentNodeCollection, kvp.Key, kvp.Value); } }
/// <summary> /// Load the list (given by owner and sFieldName) from the given TextReader. /// </summary> public void ImportList(ICmObject owner, string sFieldName, TextReader reader, IProgress progress) { m_cache = owner.Cache; m_mdc = m_cache.MetaDataCache; m_wsf = m_cache.WritingSystemFactory; m_progress = progress; NonUndoableUnitOfWorkHelper.DoUsingNewOrCurrentUOW(m_cache.ActionHandlerAccessor, () => { int flidList = m_mdc.GetFieldId(owner.ClassName, sFieldName, true); if (flidList == 0) throw new Exception(String.Format("Invalid list fieldname (programming error): {0}", sFieldName)); using (var xrdr = XmlReader.Create(reader)) { xrdr.MoveToContent(); if (xrdr.Name != owner.ClassName) throw new Exception(String.Format("Unexpected outer element: {0}", xrdr.Name)); if (!xrdr.ReadToDescendant(sFieldName)) throw new Exception(String.Format("Unexpected second element: {0}", xrdr.Name)); if (!xrdr.ReadToDescendant("CmPossibilityList")) throw new Exception(String.Format("Unexpected third element: {0}", xrdr.Name)); ICmPossibilityList list; int hvo = m_cache.MainCacheAccessor.get_ObjectProp(owner.Hvo, flidList); if (hvo == 0) hvo = m_cache.MainCacheAccessor.MakeNewObject(CmPossibilityListTags.kClassId, owner.Hvo, flidList, -2); ICmPossibilityListRepository repo = m_cache.ServiceLocator.GetInstance<ICmPossibilityListRepository>(); list = repo.GetObject(hvo); string sItemClassName = "CmPossibility"; xrdr.Read(); while (xrdr.Depth == 3) { xrdr.MoveToContent(); if (xrdr.Depth < 3) break; switch (xrdr.Name) { case "Description": SetMultiStringFromXml(xrdr, list.Description); break; case "Name": SetMultiUnicodeFromXml(xrdr, list.Name); break; case "Abbreviation": SetMultiUnicodeFromXml(xrdr, list.Abbreviation); break; case "Depth": list.Depth = ReadIntFromXml(xrdr); break; case "DisplayOption": list.DisplayOption = ReadIntFromXml(xrdr); break; case "HelpFile": list.HelpFile = ReadUnicodeFromXml(xrdr); break; case "IsClosed": list.IsClosed = ReadBoolFromXml(xrdr); break; case "IsSorted": list.IsSorted = ReadBoolFromXml(xrdr); break; case "IsVernacular": list.IsVernacular = ReadBoolFromXml(xrdr); break; case "ItemClsid": list.ItemClsid = ReadIntFromXml(xrdr); sItemClassName = m_mdc.GetClassName(list.ItemClsid); break; case "ListVersion": list.ListVersion = ReadGuidFromXml(xrdr); break; case "PreventChoiceAboveLevel": list.PreventChoiceAboveLevel = ReadIntFromXml(xrdr); break; case "PreventDuplicates": list.PreventDuplicates = ReadBoolFromXml(xrdr); break; case "PreventNodeChoices": list.PreventNodeChoices = ReadBoolFromXml(xrdr); break; case "UseExtendedFields": list.UseExtendedFields = ReadBoolFromXml(xrdr); break; case "WsSelector": list.WsSelector = ReadIntFromXml(xrdr); break; case "Possibilities": LoadPossibilitiesFromXml(xrdr, list, sItemClassName); break; case "HeaderFooterSets": throw new Exception("We don't (yet?) handle HeaderFooterSets for CmPossibilityList (programming issue)"); case "Publications": throw new Exception("We don't (yet?) handle Publications for CmPossibilityList (programming issue)"); default: throw new Exception(String.Format("Unknown field element in CmPossibilityList: {0}", xrdr.Name)); } } xrdr.Close(); if (m_mapRelatedDomains.Count > 0) SetRelatedDomainsLinks(); } }); }
/// <summary> /// Load the list (given by owner and sFieldName) from the given TextReader. /// </summary> public void ImportList(ICmObject owner, string sFieldName, TextReader reader, IProgress progress) { m_cache = owner.Cache; m_mdc = m_cache.MetaDataCache; m_wsf = m_cache.WritingSystemFactory; m_progress = progress; NonUndoableUnitOfWorkHelper.DoUsingNewOrCurrentUOW(m_cache.ActionHandlerAccessor, () => { int flidList = m_mdc.GetFieldId(owner.ClassName, sFieldName, true); if (flidList == 0) { throw new Exception(String.Format("Invalid list fieldname (programming error): {0}", sFieldName)); } using (var xrdr = XmlReader.Create(reader)) { xrdr.MoveToContent(); if (xrdr.Name != owner.ClassName) { throw new Exception(String.Format("Unexpected outer element: {0}", xrdr.Name)); } if (!xrdr.ReadToDescendant(sFieldName)) { throw new Exception(String.Format("Unexpected second element: {0}", xrdr.Name)); } if (!xrdr.ReadToDescendant("CmPossibilityList")) { throw new Exception(String.Format("Unexpected third element: {0}", xrdr.Name)); } ICmPossibilityList list; int hvo = m_cache.MainCacheAccessor.get_ObjectProp(owner.Hvo, flidList); if (hvo == 0) { hvo = m_cache.MainCacheAccessor.MakeNewObject(CmPossibilityListTags.kClassId, owner.Hvo, flidList, -2); } ICmPossibilityListRepository repo = m_cache.ServiceLocator.GetInstance <ICmPossibilityListRepository>(); list = repo.GetObject(hvo); string sItemClassName = "CmPossibility"; xrdr.Read(); while (xrdr.Depth == 3) { xrdr.MoveToContent(); if (xrdr.Depth < 3) { break; } switch (xrdr.Name) { case "Description": SetMultiStringFromXml(xrdr, list.Description); break; case "Name": SetMultiUnicodeFromXml(xrdr, list.Name); break; case "Abbreviation": SetMultiUnicodeFromXml(xrdr, list.Abbreviation); break; case "Depth": list.Depth = ReadIntFromXml(xrdr); break; case "DisplayOption": list.DisplayOption = ReadIntFromXml(xrdr); break; case "HelpFile": list.HelpFile = ReadUnicodeFromXml(xrdr); break; case "IsClosed": list.IsClosed = ReadBoolFromXml(xrdr); break; case "IsSorted": list.IsSorted = ReadBoolFromXml(xrdr); break; case "IsVernacular": list.IsVernacular = ReadBoolFromXml(xrdr); break; case "ItemClsid": list.ItemClsid = ReadIntFromXml(xrdr); sItemClassName = m_mdc.GetClassName(list.ItemClsid); break; case "ListVersion": list.ListVersion = ReadGuidFromXml(xrdr); break; case "PreventChoiceAboveLevel": list.PreventChoiceAboveLevel = ReadIntFromXml(xrdr); break; case "PreventDuplicates": list.PreventDuplicates = ReadBoolFromXml(xrdr); break; case "PreventNodeChoices": list.PreventNodeChoices = ReadBoolFromXml(xrdr); break; case "UseExtendedFields": list.UseExtendedFields = ReadBoolFromXml(xrdr); break; case "WsSelector": list.WsSelector = ReadIntFromXml(xrdr); break; case "Possibilities": LoadPossibilitiesFromXml(xrdr, list, sItemClassName); break; case "HeaderFooterSets": throw new Exception("We don't (yet?) handle HeaderFooterSets for CmPossibilityList (programming issue)"); case "Publications": throw new Exception("We don't (yet?) handle Publications for CmPossibilityList (programming issue)"); default: throw new Exception(String.Format("Unknown field element in CmPossibilityList: {0}", xrdr.Name)); } } xrdr.Close(); if (m_mapRelatedDomains.Count > 0) { SetRelatedDomainsLinks(); } } }); }
/// <summary> /// make sure we can get a PartNode for this child, if not, /// try to (recursively) generate parts refering to the parent(s) until we can find the owner of the layout. /// /// clone this (generic) part: /// /// <code> /// <part id="{className}-Jt-$fieldName" type="jtview"> /// <obj class="{className}" field="{OwnerOfClassVirtualProperty}" layout="$fieldName"/> /// </part> /// </code> /// /// into this (specific) part: /// /// <code> /// <part id="{className}-Jt-{layoutName}" type="jtview"> /// <obj class="{className}" field="{OwnerOfClassVirtualProperty}" layout="{layoutName}"/> /// </part> /// </code> /// </summary> /// <param name="layoutClass"></param> /// <param name="fieldNameForReplace"></param> /// <param name="fieldIdForWs"></param> /// <param name="layoutNode"></param> /// <returns>list of part nodes generated</returns> protected List <XmlNode> GeneratePartsFromLayouts(int layoutClass, string fieldNameForReplace, int fieldIdForWs, ref XmlNode layoutNode) { if (m_vc == null || layoutClass == 0) { return(null); } string layout = XmlUtils.GetOptionalAttributeValue(layoutNode, "layout"); if (layout == null) { return(null); } string className = m_mdc.GetClassName(layoutClass); string layoutGeneric = ""; string layoutSpecific = ""; if (layout.Contains("$fieldName") && !fieldNameForReplace.Contains("$fieldName")) { // this is generic layout name that requires further specification. layoutGeneric = layout; // first try to substitute the field name to see if we can get an existing part. XmlNode layoutNodeForCustomField = layoutNode.CloneNode(true); ReplaceParamsInAttributes(layoutNodeForCustomField, "", fieldNameForReplace, fieldIdForWs, className); layoutSpecific = XmlUtils.GetOptionalAttributeValue(layoutNodeForCustomField, "layout"); } else { // possibly need to look for the most generic layout name by default. layoutGeneric = "$fieldName"; layoutSpecific = layout; } XmlNode partNode = m_vc.GetNodeForPart(layoutSpecific, false, layoutClass); if (partNode != null) { // Enhance: Validate existing part! // specific part already exists, just keep it. return(null); } // couldn't find a specific part, so get the generic part in order to generate the specific part partNode = m_vc.GetNodeForPart(layoutGeneric, false, layoutClass); if (partNode == null) #if !__MonoCS__ { throw new ApplicationException("Couldn't find generic Part (" + className + "-Jt-" + layout + ")"); } #else { // TODO-Linux: Fix this in the correct way. return(null); } #endif if (partNode != null) { var generatedParts = new List <XmlNode>(); // clone the generic node so we can substitute any attributes that need to be substituted. XmlNode generatedPartNode = partNode.CloneNode(true); ReplaceParamsInAttributes(generatedPartNode, "", fieldNameForReplace, fieldIdForWs, className); Inventory.GetInventory("parts", m_vc.Cache.ProjectId.Name).AddNodeToInventory(generatedPartNode); generatedParts.Add(generatedPartNode); // now see if we need to create other parts from further generic layouts. if (fieldNameForReplace.Contains("$fieldName")) { // use the generated part, since it contains a template reference. partNode = generatedPartNode; } XmlNode nextLayoutNode = null; XmlAttribute layoutAttr = partNode.Attributes["layout"]; if (layoutAttr != null && layoutAttr.Value.Contains("$fieldName")) { nextLayoutNode = partNode; } else if (partNode.ChildNodes.Count > 0) { nextLayoutNode = partNode.SelectSingleNode(".//*[contains(@layout, '$fieldName')]"); } if (nextLayoutNode != null) { // now build the new node from its layouts string fieldName = XmlUtils.GetManditoryAttributeValue(nextLayoutNode, "field"); int field = m_vc.Cache.DomainDataByFlid.MetaDataCache.GetFieldId(className, fieldName, true); int nextLayoutClass = m_vc.Cache.GetDestinationClass(field); List <XmlNode> furtherGeneratedParts = GeneratePartsFromLayouts(nextLayoutClass, fieldNameForReplace, fieldIdForWs, ref nextLayoutNode); if (furtherGeneratedParts != null) { generatedParts.AddRange(furtherGeneratedParts); } } return(generatedParts); } return(null); }
int MakeRealObject(ITsString tssTyped) { // Figure whether owning atomic or owning collection or owning sequence. Throw if none. // Unless we're making an unowned IText for a Notebook Record. ISilDataAccess sdaReal = m_fdoCache.DomainDataByFlid; IFwMetaDataCache mdc = sdaReal.MetaDataCache; CellarPropertyType typeOwning = (CellarPropertyType)(mdc.GetFieldType(m_flidEmptyProp) & (int)CellarPropertyTypeFilter.VirtualMask); // Make a new object of the specified class in the specified property. int ord = 0; switch (typeOwning) { default: if (m_flidEmptyProp != RnGenericRecTags.kflidText) { throw new Exception("ghost string property must be owning object property"); } break; case CellarPropertyType.OwningAtomic: ord = -2; break; case CellarPropertyType.OwningCollection: ord = -1; break; case CellarPropertyType.OwningSequence: // ord = 0 set above (inserting the first and only object at position 0). break; } string sClassRaw = mdc.GetClassName(m_clidDst); string sClass = m_mediator.StringTbl.GetString(sClassRaw, "ClassNames"); string sUndo = String.Format(DetailControlsStrings.ksUndoCreate0, sClass); string sRedo = String.Format(DetailControlsStrings.ksRedoCreate0, sClass); int hvoNewObj = 0; int hvoStringObj = 0; UndoableUnitOfWorkHelper.DoUsingNewOrCurrentUOW(sUndo, sRedo, m_fdoCache.ServiceLocator.GetInstance <IActionHandler>(), () => { // Special case: if we just created a Text in RnGenericRecord, and we want to show the contents // of an StTxtPara, make the intermediate objects if (m_flidEmptyProp == RnGenericRecTags.kflidText) { var servLoc = Cache.ServiceLocator; var text = servLoc.GetInstance <ITextFactory>().Create(); var stText = servLoc.GetInstance <IStTextFactory>().Create(); text.ContentsOA = stText; var para = servLoc.GetInstance <IStTxtParaFactory>().Create(); stText.ParagraphsOS.Add(para); hvoNewObj = text.Hvo; hvoStringObj = para.Hvo; // Set the RnGenericRec's Text property to reference the new text sdaReal.SetObjProp(m_hvoObj, m_flidEmptyProp, hvoNewObj); } else { hvoNewObj = hvoStringObj = sdaReal.MakeNewObject(m_clidDst, m_hvoObj, m_flidEmptyProp, ord); } // Set its property m_flidStringProp to tssTyped. If it is multilingual, choose based on ghostWs. var typeString = (CellarPropertyType)(mdc.GetFieldType(m_flidStringProp) & (int)CellarPropertyTypeFilter.VirtualMask); switch (typeString) { default: throw new Exception("ghost property must store strings!"); case CellarPropertyType.MultiString: case CellarPropertyType.MultiUnicode: sdaReal.SetMultiStringAlt(hvoStringObj, m_flidStringProp, m_wsToCreate, tssTyped); break; case CellarPropertyType.String: sdaReal.SetString(hvoStringObj, m_flidStringProp, tssTyped); break; } string ghostInitMethod = XmlUtils.GetOptionalAttributeValue(m_nodeObjProp, "ghostInitMethod"); if (ghostInitMethod != null) { var obj = m_fdoCache.ServiceLocator.GetInstance <ICmObjectRepository>().GetObject(hvoNewObj); Type objType = obj.GetType(); System.Reflection.MethodInfo mi = objType.GetMethod(ghostInitMethod); mi.Invoke(obj, null); } }); return(hvoNewObj); }
internal void DumpFieldInfo(IFwMetaDataCache mdc) { if (this.Depth == 0) Debug.WriteLine(""); for (int i = 0; i < this.Depth; ++i) Debug.Write(" "); if (Source != 0) { Debug.WriteLine("[" + this.Depth + "]info.Source = " + this.Source + " = " + GetFancyFieldName(this.Source, mdc)); } else { Debug.WriteLine("Root (target) class: " + mdc.GetClassName(m_targetClass)); } for (int i = 0; i < this.AtomicFields.Count; ++i) { for (int j = 0; j < this.Depth; ++j) Debug.Write(" "); Debug.WriteLine(" Atomic[" + i + "] flid = " + this.AtomicFields[i].flid + "(" + GetFancyFieldName(this.AtomicFields[i].flid, mdc) + "); ws = " + this.AtomicFields[i].ws); } for (int i = 0; i < this.SeqFields.Count; ++i) this.SeqFields[i].DumpFieldInfo(mdc); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Gets the node. /// </summary> /// <param name="clsid">The CLSID.</param> /// <param name="layoutName">Name of the layout.</param> /// <param name="fIncludeLayouts">if set to <c>true</c> [f include layouts].</param> /// <returns></returns> /// ------------------------------------------------------------------------------------ public XmlNode GetNode(int clsid, string layoutName, bool fIncludeLayouts) { Tuple <int, string, bool> key = Tuple.Create(clsid, layoutName, fIncludeLayouts); if (m_map.ContainsKey(key)) { return(m_map[key]); } XmlNode node; int classId = clsid; string useName = layoutName ?? "default"; string origName = useName; for ( ; ;) { string classname = m_mdc.GetClassName(classId); if (fIncludeLayouts) { // Inventory of layouts has keys class, type, name node = m_layoutInventory.GetElement("layout", new[] { classname, "jtview", useName, null }); if (node != null) { break; } } // inventory of parts has key id. node = m_partInventory.GetElement("part", new[] { classname + "-Jt-" + useName }); if (node != null) { break; } if (classId == 0 && useName == origName) { // This is somewhat by way of robustness. When we generate a modified layout name we should generate // a modified layout to match. If something slips through the cracks, use the unmodified original // view in preference to a default view of Object. int index = origName.IndexOfAny(ktagMarkers); if (index > 0) { useName = origName.Substring(0, index); classId = clsid; continue; } } if (classId == 0 && useName != "default") { // Nothing found all the way to CmObject...try default layout. useName = "default"; classId = clsid; continue; // try again with the main class, don't go to its base class at once. } if (classId == 0) { if (fIncludeLayouts) { // Really surprising...default view not found on CmObject?? throw new ApplicationException("No matching layout found for class " + classname + " jtview layout " + origName); } // okay to not find specific custom parts...we can generate them. return(null); } // Otherwise try superclass. classId = m_mdc.GetBaseClsId(classId); } m_map[key] = node; // find faster next time! return(node); }
int MakeRealObject(ITsString tssTyped) { // Figure whether owning atomic or owning collection or owning sequence. Throw if none. IFwMetaDataCache mdc = m_fdoCache.MetaDataCacheAccessor; FieldType iType = m_fdoCache.GetFieldType(m_flidEmptyProp); iType &= FieldType.kcptVirtualMask; ISilDataAccess sdaReal = m_fdoCache.MainCacheAccessor; // Make a new object of the specified class in the specified property. int ord = 0; switch (iType) { default: throw new Exception("ghost string property must be owning object property"); case FieldType.kcptOwningAtom: ord = -2; break; case FieldType.kcptOwningCollection: ord = -1; break; case FieldType.kcptOwningSequence: // ord = 0 set above (inserting the first and only object at position 0). break; } string sClassRaw = mdc.GetClassName((uint)m_clidDst); string sClass = m_mediator.StringTbl.GetString(sClassRaw, "ClassNames"); string sUndo = String.Format(DetailControlsStrings.ksUndoCreate0, sClass); string sRedo = String.Format(DetailControlsStrings.ksRedoCreate0, sClass); sdaReal.BeginUndoTask(sUndo, sRedo); int hvoNewObj = sdaReal.MakeNewObject((int)m_clidDst, m_hvoObj, m_flidEmptyProp, ord); // Set its property m_flidStringProp to tssTyped. If it is multilingual, choose based on ghostWs. FieldType iTypeString = m_fdoCache.GetFieldType(m_flidStringProp); iTypeString &= FieldType.kcptVirtualMask; switch (iTypeString) { default: throw new Exception("ghost property must store strings!"); case FieldType.kcptMultiString: case FieldType.kcptMultiBigString: case FieldType.kcptMultiUnicode: case FieldType.kcptMultiBigUnicode: sdaReal.SetMultiStringAlt(hvoNewObj, m_flidStringProp, m_wsToCreate, tssTyped); break; case FieldType.kcptString: case FieldType.kcptBigString: sdaReal.SetString(hvoNewObj, m_flidStringProp, tssTyped); break; } string ghostInitMethod = XmlUtils.GetOptionalAttributeValue(m_nodeObjProp, "ghostInitMethod"); if (ghostInitMethod != null) { ICmObject obj = CmObject.CreateFromDBObject(m_fdoCache, hvoNewObj); Type objType = obj.GetType(); System.Reflection.MethodInfo mi = objType.GetMethod(ghostInitMethod); mi.Invoke(obj, null); } // Issue PropChanged for the addition of the new object. (could destroy this). sdaReal.PropChanged(null, (int)PropChangeType.kpctNotifyAll, m_hvoObj, m_flidEmptyProp, 0, 1, 0); sdaReal.EndUndoTask(); return(hvoNewObj); }