/// <summary> /// Takes the information from a dummy object and allows its owner to create a real object in the database. /// NOTE: after calling this, users need to make sure they no longer try to use the old hvoDummy object. /// </summary> /// <param name="fcCache"></param> /// <param name="hvoDummy">id corresponding to the object to convert. Minimally it should have a class id cached /// and an OwningFlid corresponding to a virtual handler that implements IDummyRequestConversion. </param> /// <returns>real object based on new database entry created for the dummy object, /// null if conversion did not take place.</returns> public static ICmObject ConvertDummyToReal(FdoCache fcCache, int hvoDummy) { // suppress changes in display. using (new IgnorePropChanged(fcCache, PropChangedHandling.SuppressView)) { // This conversion should not be an undoable task, so suppress the action handler. // (cf. LT-5330, LT-5417). using (SuppressSubTasks supressActionHandler = new SuppressSubTasks(fcCache, true)) { ICmObject realObj = null; Debug.Assert(fcCache.IsDummyObject(hvoDummy)); if (fcCache.IsDummyObject(hvoDummy)) { // see if we can convert this to a real object before loading it. int owningFlid = fcCache.GetOwningFlidOfObject(hvoDummy); IVwVirtualHandler vh = fcCache.VwCacheDaAccessor.GetVirtualHandlerId(owningFlid); Debug.Assert(vh != null && vh is IDummyRequestConversion); if (vh != null && vh is IDummyRequestConversion) { RequestConversionToRealEventArgs args = new RequestConversionToRealEventArgs(hvoDummy, 0, null, true); args.OwningFlid = owningFlid; (vh as IDummyRequestConversion).OnRequestConversionToReal(hvoDummy, args); realObj = args.RealObject as ICmObject; } } return realObj; } } }
/// <summary> /// Convert the new selection into a real object before making any selection. /// Otherwise the views code might convert it during the selection, making the selection invalid. /// </summary> /// <param name="index"></param> /// <returns></returns> private int GetNewSelectionObject(int index) { if (index < 0) return 0; int hvoObjNewSel = m_fdoCache.MainCacheAccessor.get_VecItem(m_hvoRoot, m_fakeFlid, index); if (Cache.IsDummyObject(hvoObjNewSel) && m_nodeSpec != null && XmlUtils.GetOptionalBooleanAttributeValue(m_nodeSpec, "convertDummiesSelected", false) == true) { RequestConversionToRealEventArgs args = new RequestConversionToRealEventArgs(hvoObjNewSel, 0, m_nodeSpec, true); args.OwningFlid = m_fakeFlid; m_xbvvc.OnRequestConversionToReal(this, args); if (args.RealObject != null) { if (hvoObjNewSel == m_hvoOldSel) m_hvoOldSel = args.RealObject.Hvo; hvoObjNewSel = args.RealObject.Hvo; } } return hvoObjNewSel; }
/// <summary> /// Try to convert a dummy object to a real object. /// </summary> /// <param name="sender"></param> /// <param name="args"></param> public void OnRequestConversionToReal(object sender, RequestConversionToRealEventArgs args) { CheckDisposed(); IVwVirtualHandler vh = m_cache.VwCacheDaAccessor.GetVirtualHandlerId(args.DataFlid); // let the owning list convert this to a real object, if it can and wants to. if (vh == null) { // try the virtual handler of the flid that owns this dummy object. int owningFlid = m_cache.GetOwningFlidOfObject(args.DummyHvo); args.OwningFlid = owningFlid; vh = m_cache.VwCacheDaAccessor.GetVirtualHandlerId(owningFlid); } if (vh != null && vh is IDummyRequestConversion) { ISilDataAccess sda = m_cache.MainCacheAccessor; // As we do the conversion, it's important to get these three pseudo-properties into the EXACT // same state for the new object as for the dummy. I'm not sure about the other two, but especially // for wasChecked, just reading it and writing it is not good enough, because we'll get a default // of zero (unchecked) if it isn't in the cache at all, but possibly we are depending on code // that treats it as CHECKED if it isn't cached at all. bool fWasCheckedCached = sda.get_IsPropInCache(args.DummyHvo, XmlBrowseViewVc.ktagItemSelected, (int)CellarModuleDefns.kcptInteger, 0); int wasChecked = 0; if (fWasCheckedCached) wasChecked = m_cache.MainCacheAccessor.get_IntProp(args.DummyHvo, XmlBrowseViewVc.ktagItemSelected); bool fWasEnabledCached = sda.get_IsPropInCache(args.DummyHvo, XmlBrowseViewVc.ktagItemEnabled, (int)CellarModuleDefns.kcptInteger, 0); int wasEnabled = 0; if (fWasEnabledCached) wasEnabled = m_cache.MainCacheAccessor.get_IntProp(args.DummyHvo, XmlBrowseViewVc.ktagItemEnabled); bool fWasPreviewCached = sda.get_IsPropInCache(args.DummyHvo, XmlBrowseViewVc.ktagAlternateValue, (int)CellarModuleDefns.kcptString, 0); ITsString tssPreview = null; if (fWasPreviewCached) tssPreview = m_cache.MainCacheAccessor.get_StringProp(args.DummyHvo, ktagAlternateValue); (vh as IDummyRequestConversion).OnRequestConversionToReal(this, args); if (args.RealObject != null) { if (fWasCheckedCached) m_cache.VwCacheDaAccessor.CacheIntProp(args.RealObject.Hvo, XmlBrowseViewVc.ktagItemSelected, wasChecked); if (fWasEnabledCached) m_cache.VwCacheDaAccessor.CacheIntProp(args.RealObject.Hvo, XmlBrowseViewVc.ktagItemEnabled, wasEnabled); if (fWasPreviewCached) m_cache.VwCacheDaAccessor.CacheStringProp(args.RealObject.Hvo, ktagAlternateValue, tssPreview); } } }
/// <summary> /// Called to ensure data is loaded for a lazily-displayed object we are about to use. /// </summary> /// <param name="vwenv"></param> /// <param name="rghvo"></param> /// <param name="chvo"></param> /// <param name="hvoParent"></param> /// <param name="tag"></param> /// <param name="frag"></param> /// <param name="ihvoMin"></param> public override void LoadDataFor(IVwEnv vwenv, int[] rghvo, int chvo, int hvoParent, int tag, int frag, int ihvoMin) { CheckDisposed(); // Have FDO load the object to make sure its properties are in the cache. foreach (int hvo in rghvo) { try { LoadDataForObject(hvo); } catch (Exception) { if (!m_cache.IsValidObject(hvo)) { MessageBox.Show(m_xbv, XMLViewsStrings.ksDeletedObjectMsg, XMLViewsStrings.ksDeletedObject, MessageBoxButtons.OK, MessageBoxIcon.Warning); if (m_xbv != null && m_xbv.Mediator != null) m_xbv.Mediator.BroadcastMessage("Refresh", null); return; } throw; } // It might be useful to make real objects out of any dummy ones we can see. This is controlled by // an attribute of the XML file, convertDummiesInView, so it may do nothing at all. Note that this // happens in the background (if at all); it isn't guaranteed that objects we can see are real. // Enabling it may cause somewhat erratic behavior in the scroll bar as the substitutions are made. // For this reason it is currently (Mar 2008) turned off in the XML. if (m_cache.IsDummyObject(hvo) && this.InOnPaint && m_xbv.ShouldConvertDummiesInView()) { RequestConversionToRealEventArgs args = new RequestConversionToRealEventArgs(hvo, tag, null, false); OnRequestConversionToReal(this, args); } } }
void DummyRecordList_RequestConversionToReal(object sender, RequestConversionToRealEventArgs e) { // Make sure we aren't in the process of making a selection, since that selection will become invalid // if we convert its root object. // take any pending request if (m_fPendingConversionRequest) m_fPendingConversionRequest = false; // To generate the parser data for this object, we need to convert it to a real object. // The ParserListener should detect that a real property that it knows the Parser cares about // has been detected, and will schedule it to be parsed through the ParserConnection. bool fRequiresRealParserGeneratedData = false; if (e.Configuration != null) { fRequiresRealParserGeneratedData = XmlUtils.GetOptionalBooleanAttributeValue(e.Configuration, "requiresRealParserGeneratedData", false); } // first see if the conversion has already been done. if so, just update our lists. if (e.RealObject != null) { // we just want to replace the dummy in our list ArrayList newSortItems = new ArrayList(); ReplaceDummyItemWithReal(e.OwningFlid, e.DummyHvo, e.RealObject, ref newSortItems); if (newSortItems.Count > 0) SendPropChangedOnListChange(CurrentIndex, SortedObjects, ListChangedEventArgs.ListChangedActions.SkipRecordNavigation); } else if (e.ConvertNow) { // see if we've already converted this value. if so, just return the result. ICmObject realObj = null; if (!m_dummyToRealDict.TryGetValue(e.DummyHvo, out realObj)) { m_dummyToRealDict.Add(e.DummyHvo, null); } if (realObj == null) { // insert at the top of the list, to give this one priority. m_requestedDummiesToConvertQueue.Insert(0, e.DummyHvo); // we'll take responsibility for the conversion. e.RealObject = ConvertDummyToReal(e.OwningFlid, e.DummyHvo); } else { e.RealObject = realObj; } } else if (fRequiresRealParserGeneratedData || sender is XmlVc) { // if the sender is XmlVc, assume we're trying to load the information on demand. // add it to our queue for converting and issuing a PropChanged for our list when safe to do so. // plus, its probably faster to do several conversions at once, rather than one at a time. // we don't want to do a conversion and PropChanged while Drawing, because the views objects can still be // using and depending upon the old objects. if (!m_dummyToRealDict.ContainsKey(e.DummyHvo)) { m_dummyToRealDict.Add(e.DummyHvo, null); m_requestedDummiesToConvertQueue.Add(e.DummyHvo); // add to the end (Enqueue). m_dummiesToConvertRequestsMap[e.DummyHvo] = e; } } // Enhance: Should we only create a real object if the parser has been started? }
/// <summary> /// /// </summary> /// <param name="hvo"></param> /// <param name="tag"></param> /// <param name="ws"></param> /// <param name="cda"></param> public override void Load(int hvo, int tag, int ws, IVwCacheDa cda) { if (BaseVirtualHandler.ForceBulkLoadIfPossible && m_bulkMethodInfo != null && m_bulkValues == null) { SetLoadForAllOfClass(true); BaseVirtualHandler.m_rgvhBulkForced.Add(this); } ICmObject fdoObj = null; if (m_cache.IsDummyObject(hvo)) { RequestConversionToRealEventArgs args = new RequestConversionToRealEventArgs(hvo, tag, m_configuration, false); OnRequestConversionToReal(this, args); fdoObj = args.RealObject; // null, if no conversion took place. } if (fdoObj == null) { fdoObj = CmObject.CreateFromDBObject(m_cache, hvo); } int nVal = 0; if (m_bulkMethodInfo != null && m_bulkValues != null) { if (!m_fBulkLoaded) { m_bulkMethodInfo.Invoke(null, new object[] { m_cache, m_bulkValues }); m_fBulkLoaded = true; } if (!m_bulkValues.TryGetValue(hvo, out nVal)) nVal = 0; } else { nVal = (int)m_propertyInfo.GetValue(fdoObj, null); } cda.CacheIntProp(hvo, tag, nVal); }
/// <summary> /// Raises the RequestConversionToReal event with the given arguments. /// </summary> /// <param name="sender"></param> /// <param name="args"></param> public void OnRequestConversionToReal(object sender, RequestConversionToRealEventArgs args) { try { int owningFlid = args.OwningFlid; if (RequestConversionToReal != null) { RequestConversionToReal(sender, args); } else { if (sender == this || args.ConvertNow == true) { // try the virtual handler of the flid that owns this dummy object. if (args.OwningFlid == 0) owningFlid = m_cache.GetOwningFlidOfObject(args.DummyHvo); IVwVirtualHandler vh = m_cache.VwCacheDaAccessor.GetVirtualHandlerId(owningFlid); if (vh != null && sender != this && vh is IDummyRequestConversion) { (vh as IDummyRequestConversion).OnRequestConversionToReal(this, args); } } } if (args.ConvertNow == true && (args.RealObject == null || args.RealObject.IsDummyObject)) { // as a last resort, try to call the owner directly. int hvoOwner = m_cache.GetOwnerOfObject(args.DummyHvo); Debug.Assert(hvoOwner != 0); ICmObject owner = CmObject.CreateFromDBObject(m_cache, hvoOwner); if (owner is IDummy) { args.RealObject = (owner as IDummy).ConvertDummyToReal(owningFlid, args.DummyHvo); } } } finally { if (args.ConvertNow == true && (args.RealObject == null || args.RealObject.IsDummyObject)) throw new ApplicationException("We couldn't find someone to handle converting this dummy (" + args.DummyHvo + ") to a real."); } }