[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?

  • 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 

  • Thanks Jon,

    No way I would have found this on my own.

  • 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

  • Maybe it's because you create infinitive events recursion?

    That's a definite possibility.

    No way I would have found this on my own

    Why isn't the same documentation in both the MicroStationAPI and the DgnPlatformNet?

    It's quite hard to find even in the MicroStationAPI.  My approach is to use the Search pane and find the struct item (struct == class, more or less, in C++).  Clicking on xxxx struct pops useful help along with a link to the header file.  Sometimes you'll find more information, such as the snippet I posted.

    Just to keep us on our collective toes, the help and examples are not always where one expects.  For example, the TextBlock API is rather terse, but look in the mdlText_deprecated API and you find lots of examples about — TextBlock!

    I am trying to update an Item Type property

    One approach is to obey the documentation and not modify anything in the Change Track event.  The 'proper' way would be to write the equivalent of a SYSTEM_ELMDSCR_TO_FILE callback, if that were available.

    A workaround is to queue a hidden command in your Change Track event.  The command, which must exist in your app's command table, will be executed once MicroStation's input queue is almost empty, meaning that the Change Track event will have completed.  Pass the element ID of the modified element in your command arg., then retrieve and update your Item Type properties.

    I concede that that is a clunky approach, but it may just work, Scotty!  Perhaps it would be better to let someone in Bentley Systems tell us how to write a SYSTEM_ELMDSCR_TO_FILE callback using C#.

     
    Regards, Jon Summers
    LA Solutions

  • More importantly, please tell me how to insert a blockquote when using this forum. Hmm, maybe need some community docs. Slight smile

    Jan/Jon >> events recursion.

    Possibly. I have seen evidence that this is happening.

    Jon >> A workaround is to queue a hidden command in your Change Track event.  The command, which must exist in your app's command table, will be executed once MicroStation's input queue is almost empty, meaning that the Change Track event will have completed. 

    Ok. But, don't I have to know when the change event is complete? Or, how do I know when the input queue is almost empty?

    Thanks to you both.

  • 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.