[CONNECT C#] ElementChangedEvent and Item Types

Versions: MicroStation Update 10 (10.10.00.23 and SDK 10.10.00.32).

I am trying to update an Item Type property on an element that has been moved. If I try to update the item type using a change event the code below will fail. If however, I put this code into a stand-alone command and get the collection of elements then the code runs fine. So, it seems that there is an issue updating the NewElement in the change event.

If I run it inside the change event, Change == ChangeTrackKind.Modify, the code that updates the ItemType crashes (full kill and closes MicroStation). This would be the ChangeStringPropertyOnItemType code. I thought maybe the Args.NewElement had not been written to the file yet, so I couldn't actually update it. Maybe I needed to update the Item Type when the modify was finished Change == 17 (by the way, this is missing from ChangeTrackKind). But the program still crashes when I try to make the update on Modify Finished.

static void ElementChangedInModel(object sender, ORDSignsApp.ElementChangedEventArgs Args)
{
    //...
    else if (Args.Change == AddIn.ChangeTrackKind.Modify) // move and change symbology
    {
        // test that this is a cell move otherwise return
        Element oldElm = Element.GetFromElementRef(Args.OldElementRef);
        if (!TestCellsAndEqualOrigins(oldElm, Args.NewElement)) return;

        // make sure we have cell that represents a post
        if (FdotSigns.HasPostItemType(Args.NewElement.ElementId))
        {
            // get current station label
            string s = FdotSigns.GetStringPropertyFromItemTypes(Args.NewElement, "SignPostIT", "Station");

            // is the station label populated
            if (s.Trim().Length > 0)
            {
                DPoint3d snapOrigin = new DPoint3d(.0, .0, .0);
                (Args.NewElement as CellHeaderElement).GetSnapOrigin(out snapOrigin);

                // set the active aligment - in this case the post alignment
                string aName = FdotSigns.GetStringPropertyFromItemTypes(Args.NewElement, "SignPostIT", "AlignmentName");
                if (FdotSigns.SetAlignmentFromName(aName))
                {
                    // get the new station label
                    string stationLabel = PlacementGuide.GetStation(FdotSigns.m_al, snapOrigin);

                    // update station item type - fails when run from change event
                    FdotSigns.ChangeStringPropertyOnItemType(Args.NewElement, stationLabel, "SignPostIT", "Station");
                }
            }
        }
    }
    //...
}

// update the item type property
public static void ChangeStringPropertyOnItemType(Bentley.DgnPlatformNET.Elements.Element elt, string newvalue, string itlib, string propname)
{
    try
    {
        CustomItemHost itemHost = new CustomItemHost(elt, false);
        IDgnECInstance appliedItem = itemHost.GetCustomItem("SignITL", itlib);

        if (appliedItem != null)
        {
            IECPropertyValue property = appliedItem.FindPropertyValue(propname, false, false, false);
            property.StringValue = newvalue;
            appliedItem.WriteChanges();
        }
    }
    catch (System.Exception ex)
    {
        ORDSignsApp.LogEx(ex);
    }
}

How do I know when the change event is really finished and NewElement has been written to the design file?

Parents
  • I am trying to update an Item Type property on an element that has been moved. If I try to update the item type using a change event …

    From MicroStationAPI help:

    The Change Track API is NOT intended to enable applications to "influence" or modify the changes to the DGN file (that's the purpose of the SYSTEM_ELMDSCR_TO_FILE asynch call). Obviously, many applications can monitor te Change Track events simultaneously, and the order in which they are processed is indeterminate. However, since none of them can change the information being processed, the order of execution is moot.

    So it's a bad idea to attempt to modify your Item Type properties in the ChangeTrackKind.Modify event handler.

    The system callback (SYSTEM_ELMDSCR_TO_FILE) in the C++ MicroStationAPI is SetElmDscrToFileFunction. I don't know what the equivalent is in the DgnPlatformNet or MstnPlatformNet APIs.

     
    Regards, Jon Summers
    LA Solutions

    Answer Verified By: Mark Stefanchuk 

  • The Change Track API is NOT intended to enable applications to "influence"

    A question is whether NET API is wrapper around Change Track API. My assumption is that it's not, but it's the wrapper around Transaction Manager (TxnMonitor, ITxn, ITxnManager). But I guess the APIs are old (function callbacks) and new (C++ interfaces) implementation of the same topic, so probably the same limitations exist.

    From some reasons AddComplete event is not available in ChangeTrackKind enumeration, but it's available in C++ API. Not sure whether it can help here.

    How do I know when the change event is really finished and NewElement has been written to the design file?

    If ChangeTrackKind.Modify.Modify is equal to native ChangeTRackAction.Modify, the description is: An existing element was changed and rewritten to the file in place.  So the element should be rewritten already. But it's not clear what internal implementation of the wrapper was used.

    Surprisingly there is also ModifyComplete value in native API with very similar description: An existing element (and its xattributes) were changed and rewritten to the file in place. Not available in NET enum.

    Based on this discussion it seems that ModifyComplete event is raised also in NET API.

    I don't know what the equivalent is in the DgnPlatformNet or MstnPlatformNet APIs.

    I guess not, it seems to be too low-level and resource allocating operation to be included in NET API.

    If I run it inside the change event, Change == ChangeTrackKind.Modify, the code that updates the ItemType crashes

    Maybe it's because you create infinitive events recursion? I am not sure but when you changed ItemTypes inside Element Modified event, you raised another XAtrribute changed event, which maybe wil raise Element Modified event again.

    With regards,

      Jan

  • But, don't I have to know when the change event is complete?

    Without doing (modify) anything, try to check what events are fired (values of ElementChangedEventArgs.Change). Based on the discussion I linked I assume that also event 17 maybe is reported, which should be "everything is completed".

    With regards,

      Jan

  • how do I know when the input queue is almost empty?

    Because your command bubbles to the top.  Then MicroStation executes it.  In other words, your own asynchronous callback.

     
    Regards, Jon Summers
    LA Solutions

  • Of course, the new command will stop any other command. I will implement and test.

  • the new command will stop any other command

    No.  You're thinking of a primitive command, which pre-empts an existing primitive command.  There are plenty of command classes to choose from, that are not primitive commands.

     
    Regards, Jon Summers
    LA Solutions

  • Yes. I have done this. Change 17 does occur, and I can capture by comparing the Change value directly. When I try to modify the new element here MicroStation still crashes. Will attempt Jon's command approach and report back.

  • Update: I implemented a hidden command per Jon's suggestion, and it does look like it's moving to the top of the command queue, but because I am modifying an Item Property the Change event executes again creating an endless loop. Of course this was the case calling the method directly. So, no change.

    I tried calling the command from both the Modify and Modify Finished event cases, but both appear to create the same situation. I then added a flag to break the loop after it runs one time. This worked to break the loop, but I don't have a good way to reset the flag.

    I plan to set this aside for now. Will revisit with C++ and SYSTEM_ELMDSCR_TO_FILE callback function after I get through some more pressing project issues.

    If Bentley could weigh in on the idea of creating a SYSTEM_ELMDSCR_TO_FILE callback in .Net I think we would all appreciate it.

    Also (to Bentley), any chance we can get some documentation for CommandTable.xml syntax? As a minimum can you publish an article to provide attribute and value choices for Options. And CommandClass values withan explanation of where to insert these.

    Examples show MacroCommand as a value, but there are no other examples. I can infer from cmdclass.r.h, but it doesn't show .Net values. And it's not clear whether I can add CommandClass to the SubKeyInTable Keyword tags. I'd be happy with a blog on this. (will add to ideas).

  • Hi Mark,

    my feeling (but feeling only, not based on any facts) is that something wrong is in your approach. I am not fine with the idea to change in a middle of current transaction to change other element. Maybe it's possible and there is a safe way how to do it using features of TranscationManager and TransactionMonitor (in C++), but it has to be confirmed or disproved by Bentley.

    Maybe DependencyManager would be better solution, but I have no idea whether elements with XAttributes can be monitored as dependent or not (and when yes, using what ID the dependency is stored).

    Will revisit with C++ and SYSTEM_ELMDSCR_TO_FILE callback function

    For me it's "too close" to element descriptors and file storage, both I treated "too implementation dependent", especially from perspective of abstract object approach using Handlers and EC description and new ways how data can be stored (i-model, iModelHub 2.0 etc.). But maybe there is really no other way in your situation.

    If Bentley could weigh in on the idea of creating a SYSTEM_ELMDSCR_TO_FILE callback in .Net I think we would all appreciate it.

    You can do it yourself. C++/CLI wrapper can publish delegate as a part of NET API. Personally I did it once and I remember it was not very clear for my limited knowledge of all details of C++/CLI and the best practices, but at least I am sure it's possible to transform C++ callbacks to C# delegates (or because delegates are a bit obsolete now, to Events).

    With regards,

      Jan

  • Thanks Jan,

    Yes, I am also pretty sure this is the wrong approach. That is, ChangeTrack isn't the right place. - It only appears to be convenient.

    I have limited knowledge of dependency manager. To me it seems like DependencyManager is more than I need, but, I will take a closer look.

    C++/CLI wrapper - ok sure, I can do it myself. But before I invest time in this I kind of wanted confirmation from Bentley that there is no way to handle this in C#. That's reasonable, right?

  • Hi Mark,

    I am trying to follow your steps for this problem. I will get back to you on this.

    Thanks and Regards,

    Snehal Deshpande

  • One option to delay the  WriteChanges(); call such that it would not go in recursion(but here we are not sure on sequence of element's change completion) otherwise there is no other way in C# to handle this.   

Reply Children
No Data