AccessViolationException when using DockablePane when only groups are selected

AccessViolationException when using DockablePane when only groups are selected

andhxl
Contributor Contributor
983 Views
6 Replies
Message 1 of 7

AccessViolationException when using DockablePane when only groups are selected

andhxl
Contributor
Contributor

If click anywhere inside DockablePane when only groups are in the selection, and then switch to another view by clicking on tab, will Revit crash (shown in the video).

 

This also happens if: only groups are selected -> show custom DockablePane -> switch to another view by clicking on tab.

It does not depend on the specific plugin. This happens with all custom DockablePane.

This bug is definitely in version 2020 and 2021.

I have not found this bug since version 2024.

Exception System.AccessViolationException in Revit.

How to fix it?

Accepted solutions (2)
984 Views
6 Replies
Replies (6)
Message 2 of 7

andhxl
Contributor
Contributor

Currently, I have found such a solution:
- Subscribe to Panel.CollectionChanged at the "Modify" tab (to get: Autodesk.Windows.ComponentManager.Ribbon.FindTab("Modify"));
- During the event, I determine whether "Modify" tab contains panel with Id == "Dialog_ElementGroup_EditGroupNew";
- if true, then for MFCPaneControl of my DockablePane (to get: UIFramework.MainWindow.getMainWnd().FindPaneControl(paneGuid)) for property IsEnabled set value false, else set true.

Also, if it contains this panel, then I forbid to show my DockablePane.

 

UPD: Even that doesn't solve the problem 100%( I somehow managed to get exception with this

Message 3 of 7

ricaun
Advisor
Advisor

That's a fun Exception, looks like was fixed in Revit 2023 (Revit 2022 still breaks).

 

I tested with my plugin that has a DockablePanel and in there have a TextBox, if I select that and the selection have a group like in your video, Revit breaks. I don't know if only breaks in the TextBox or other visual inside the Dockable gonna break as well.

 

Because that problem does not happen in the newer version of Revit, kinda was fixed already.
And the steps is so specific, need to select a group then select the dockable pane and change the view. I wonder what you are doing to trigger that.


You kinda can use the EditorInteraction to unselect the elements when interaction with the dockable pane, could be a way to 'fix'.

 

Luiz Henrique Cassettari

ricaun.com - Revit API Developer

AppLoader EasyConduit WireInConduit ConduitMaterial CircuitName ElectricalUtils

0 Likes
Message 4 of 7

andhxl
Contributor
Contributor

EditorInteraction with EditorInteractionType.Dismiss is not working correctly. After switching views, the selection is no longer reset (shown in the video).

 

This sequence of actions can actually happen quite often (unlike the second case, which I wrote about). DockablePane of my plugin is constantly displayed to users. The specifics of its purpose (as a project browser). In real work for the whole working day, such situations can occur quite often. Several users have sent feedback about the crash when using the plugin. I looked in the revit journal what they were doing before the crash and everyone select group.

 

The solution I wrote above (with temporary disable MFCPaneControl and banning showing DockablePane) works at 95%. It suits me, but I still hope for a better solution

Message 5 of 7

ricaun
Advisor
Advisor
Accepted solution

That's annoying that the EditorInteractionType.Dismiss does not work...

 

I kinda found a workaround by deselecting all the elements in the ViewActivating and selecting after the view finish to change in the ViewActivated.

 

At least Revit does not break anymore, but I don't know if that approach gonna have some issue when you have too many elements selected and change the view, probably would make more sense to only do that if selection have only groups.

 

Here is the basic code.

 

using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using System.Collections.Generic;

namespace RevitAddin.Revit
{
    public class AppView : IExternalApplication
    {
        public Result OnStartup(UIControlledApplication application)
        {
            application.ViewActivating += Application_ViewActivating;
            application.ViewActivated += Application_ViewActivated;
            return Result.Succeeded;
        }

        public Result OnShutdown(UIControlledApplication application)
        {
            application.ViewActivating -= Application_ViewActivating;
            application.ViewActivated -= Application_ViewActivated;
            return Result.Succeeded;
        }

        ICollection<ElementId> elementIds;
        private void Application_ViewActivating(object sender, Autodesk.Revit.UI.Events.ViewActivatingEventArgs e)
        {
            var uiapp = sender as UIApplication;
            UIDocument uidoc = uiapp.ActiveUIDocument;
            Selection selection = uidoc.Selection;
            elementIds = selection.GetElementIds();
            selection.SetElementIds(new ElementId[] { });
        }

        private void Application_ViewActivated(object sender, Autodesk.Revit.UI.Events.ViewActivatedEventArgs e)
        {
            var uiapp = sender as UIApplication;
            UIDocument uidoc = uiapp.ActiveUIDocument;
            Selection selection = uidoc.Selection;
            selection.SetElementIds(elementIds);
            elementIds = new ElementId[] { };
        }
    }
}

 

 

Maybe if you use the ViewActivating event to force your DockablePane to lose focus, maybe that do the trick.

 

Luiz Henrique Cassettari

ricaun.com - Revit API Developer

AppLoader EasyConduit WireInConduit ConduitMaterial CircuitName ElectricalUtils

Message 6 of 7

andhxl
Contributor
Contributor
Accepted solution

Thanks, the option with selection works. Lost focus didn't work for me.
As a result, it turned out something like this:

 

using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Events;
using Autodesk.Revit.UI.Selection;
using Autodesk.Windows;

namespace DockablePanes.Helpers;

public class DockablePaneHelper : IDisposable
{
    private const string GroupPanelId = "Dialog_ElementGroup_EditGroupNew";
    private static readonly RibbonTab _modifyTab = ComponentManager.Ribbon.FindTab("Modify");

    private readonly UIControlledApplication _uiapp;
    private readonly bool _hasBug;

    private ICollection<ElementId> _selectedIds;
    private bool _restoreSelection;

    public DockablePaneHelper(UIControlledApplication uiapp)
    {
        _uiapp = uiapp ?? throw new ArgumentNullException(nameof(uiapp));
        _hasBug = CheckHasBug(_uiapp);
    }

    public void Dispose()
    {
        Disable();
    }

    public bool IsEnabled { get; private set; }

    public static bool CheckHasBug(UIControlledApplication uiapp)
    {
        // The bug is fixed in Revit 2023
        if (int.TryParse(uiapp.ControlledApplication.VersionNumber, out int versionNumber))
            return versionNumber < 2023;
        return true;
    }

    public static bool CheckCrashPossible(UIControlledApplication uiapp)
    {
        if (uiapp is null || CheckHasBug(uiapp))
            return CheckCrashPossible();
        return false;
    }

    public bool Enable()
    {
        if (IsEnabled) return true;
        if (!_hasBug) return false;

        _uiapp.ViewActivating += UIApp_ViewActivating;
        _uiapp.ViewActivated += UIApp_ViewActivated;

        IsEnabled = true;
        return true;
    }

    public bool Disable()
    {
        if (!IsEnabled) return true;

        _uiapp.ViewActivating -= UIApp_ViewActivating;
        _uiapp.ViewActivated -= UIApp_ViewActivated;

        IsEnabled = false;
        return true;
    }

    /// <summary>
    /// There is a known case when only groups are selected (until Revit 2023).
    /// </summary>
    private static bool CheckCrashPossible()
    {
        // Searching for the panel that appears when only groups are selected is faster than searching for groups in the selection
        if (_modifyTab is null) return true;
        return _modifyTab.FindPanel(GroupPanelId) is not null;
    }

    private void UIApp_ViewActivating(object sender, ViewActivatingEventArgs e)
    {
        if (!CheckCrashPossible()) return;

        var uiapp = (UIApplication)sender;
        UIDocument uidoc = uiapp.ActiveUIDocument;
        if (uidoc is null) return;

        Selection selection = uidoc.Selection;
        _selectedIds = selection.GetElementIds();
        selection.SetElementIds([]);

        _restoreSelection = true;
    }

    private void UIApp_ViewActivated(object sender, ViewActivatedEventArgs e)
    {
        if (!_restoreSelection) return;

        var uiapp = (UIApplication)sender;
        uiapp.ActiveUIDocument?.Selection.SetElementIds(_selectedIds);

        _selectedIds = null;
        _restoreSelection = false;
    }
}

 

UPD: Added a version check, thanks

Message 7 of 7

ricaun
Advisor
Advisor

Neat! I like your service implementation looks similar how I do it.

 

One thing I would add is to only enable/start this service if version of Revit is 2022 or lower.

 

Something like this inside the Start to not enable the service if the version is 2023 or greater.

// The bug is fixed in Revit 2023
if (int.TryParse(_uiApp.ControlledApplication.VersionNumber, out int versionNumber) && versionNumber >= 2023)
    return false;

 

Without that the SelectionChanged event trigger again if you change the view, and SelectionChanged was added in 2023 the same year this problem does not happen anymore.

 

Luiz Henrique Cassettari

ricaun.com - Revit API Developer

AppLoader EasyConduit WireInConduit ConduitMaterial CircuitName ElectricalUtils