Jon,
Maybe you should post your code? One of the main reasons DgnElementSetTool was created was to make it so that tools could be mostly agnostic about where the elements originated, be it single locate, graphic group. named group, fence, or selection set.
It sounds like you are possibly writing to the DgnModel inside your _OnElementModify (instead of just updating the EditElementHandle)...and also have element dynamics enabled?
To support fences, you should return USES_FENCE_Required or USES_FENCE_Check from _AllowFence. In _OnElementModify, you should just update the EditElementHandle that is passed to you. _OnElementModify is called for both dynamics and for the final accept, DgnElementSetTool will take care of displaying the modified element or updating the file for you.
NOTE: If your tool requires dynamics and you also need to distinguish between dynamics and the final accept, you can override _OnRedrawOperation so that it doesn't just call _OnElementModify.
/*---------------------------------------------------------------------------------**//** * Called during complex dynamics. Default implementation calls _OnElementModify and * assumes it's not valid to display the modified element using an existing cache * representation. * @param el IN Current element. * @param context IN context for the redraw operation. * @param canUseCached OUT whether cached representation is still valid for display. * @return SUCCESS to not skip the display of the current element. * @see IRedrawOperation * @bsimethod +---------------+---------------+---------------+---------------+---------------+------*/ DGNVIEW_EXPORT virtual StatusInt _OnRedrawOperation (EditElementHandleR el, ViewContextR context, bool* canUseCached) override;
If you don't want dynamics return false from _WantDynamics. You might also want to then override _NeedAcceptPoint if you require an explicit data button to accept the fence, since by default it's not required to accept a fence or selection set when the tool isn't starting dynamics.
/*---------------------------------------------------------------------------------**//** * Called after populating tool's ElementAgenda to see if an explict data point * is required before accepting and calling _ProcessAgenda. By default an accept point * is required for tools that return true for WantDynamics, or for SOURCE_PICK when * the user has Auto-Locate disabled. * @return true to delay calling _ProcessAgenda until the next data point. * @bsimethod +---------------+---------------+---------------+---------------+---------------+------*/ DGNVIEW_EXPORT virtual bool _NeedAcceptPoint ();
When the tool operation is complete/accepted, then _OnModifyComplete will be called after _ProcessAgenda. Below is the documention from DgnElementSetTool.h detailing what methods are called when accepting the selected elements:
The following sequence of member function calls will occur in the case where the tool requires a single datapoint to identify the target element and to accept the modification (#_NeedAcceptPoint -> false, #_WantDynamics -> false):<ul><li>#_OnPostInstall</li><ul><li>#_SetupAndPromptForNextAction -- empty agenda</li></ul><li>#_OnDataButton</li><ul><li>#_LocateOneElement</li><ul><li>#_DoLocate</li><li>#_BuildLocateAgenda</li><li>#_ModifyAgendaEntries</li><ul><li>#_FilterAgendaEntries</li><li>#_SetupAndPromptForNextAction -- non-empty agenda</li><li>#_HiliteAgendaEntries</li></ul><li>AnchorPoint = datapoint</li></ul><li>#_ProcessAgenda</li><ul><li>#_SetupForModify -- dynamics=false</li><li>#_OnElementModify</li><li>element is written to cache</li></ul><li>#_OnModifyComplete</li><ul><li>#_OnReinitialize</li></ul></ul></ul>
NOTE: The correct way to restart your tool is to provide an implementation of _OnRestartTool that installs a new instance of your tool (see ExampleModifyTool.cpp)
/*---------------------------------------------------------------------------------**//** * Install a new instance of the tool. Will be called in response to external events * such as undo or by the base class from _OnReinitialize when the tool needs to be * reset to it's initial state. * * @bsimethod Bentley Systems +---------------+---------------+---------------+---------------+---------------+------*/ virtual void _OnRestartTool () override { InstallNewInstance (GetToolId ()); } public: /*---------------------------------------------------------------------------------**//** * Method to create and install a new instance of the tool. If InstallTool returns ERROR, * the new tool instance will be freed/invalid. Never call delete on RefCounted classes. * * @bsimethod Bentley Systems +---------------+---------------+---------------+---------------+---------------+------*/ static void InstallNewInstance (int toolId) { ExampleModifyElementTool* tool = new ExampleModifyElementTool (toolId); tool->InstallTool (); } /*---------------------------------------------------------------------------------**//** * Function that was associated with the command number for starting the tool. * * @param[in] unparsed Additional input supplied after command string. * @bsimethod Bentley Systems +---------------+---------------+---------------+---------------+---------------+------*/ Public void startExampleModifyElementTool (WCharCP unparsed) { // NOTE: Call the method to create/install the tool, RefCounted classes don't have public constructors... ExampleModifyElementTool::InstallNewInstance (CMDNAME_ExampleModifyTool); }