Addin WPF Window Stops Responding after Family Upgrade

Addin WPF Window Stops Responding after Family Upgrade

swfaust
Advocate Advocate
608 Views
1 Reply
Message 1 of 2

Addin WPF Window Stops Responding after Family Upgrade

swfaust
Advocate
Advocate

Cross posting from StackOverflow post here as no help seems to have come from there...

 

I have a strange situation with an add-in for Revit. The add-in uses a non-modal window that lists things out and among them are families. The user can choose a family to load and it then fires an external event that handles loading the family and prompting for placement.

 

All of this works fine, but if the family is not current (i.e. needs to be upgraded) it causes the UI not to update afterward. The standard Revit upgrade dialog shows up and then goes away and the user is prompted for placement of the family, but if they go back to the dialog nothing updates.

 

IMPORTANT NOTE: This is NOT a frozen UI issue or a locked thread. I can drag the window around, and if I click on any of the links in the UI that are supposed to open web pages or external sources the external sources open, so it is actually processing clicks, etc. However, when I do something that should make changes to the UI (like mouse over a button or try to click a filtering button) nothing changes.

 

To make it even stranger, if I click the link on the dialog that should bring up the 'About' dialog it comes up... and then the main UI updates and is working properly again. When the UI updates it updates to show as it should be based on the clicks I made while it was not updating so obviously it was processing correctly it just wasn't updating the dialog UI.

 

So it seems like this is some type of redraw issue and it seems to be triggered by the family upgrade dialog. I'm at a loss how to debug this though. How would I go about either debugging this or forcing a redraw or...?

 

Here is the code for showing the non-modal window:

 

//If we have a window then it's shown, just activate it for the user and return
if (_window != null)
{
    _window.Activate();
    return;
}

//Don't have a window, check if we have a model (model is cached, window is not)
if (_vm == null)
{
    //Construct a new model
    _vm = new ToolboxVM(_cacheManager, _contentProviderService, _updatesService, _settingManager,
        _imageCache);
    _vm.StartContent += (sender, content) => ExecuteContent?.Invoke(content);
}
else
{
    //We need to clear the filters, otherwise the model is filtered but the UI doesn't show it.
    _vm.ContentTypeFilter.Clear();
    _vm.IndustryFilter.Clear();
}

//Now create a window and show it
_window = new Wnd_Toolbox() {DataContext = _vm};
var unused = new WindowInteropHelper(_window) {Owner = Process.GetCurrentProcess().MainWindowHandle};
_window.Closed += (sender, e) => _window = null;
_window.Show();

 

Pressing the load button invokes this method.  It basically just downloads the file to a cache if necessary and then invokes the 'StartContent' event.  That event bubbles up to invoke the external event in Revit.

 

try
{
    if (Utility.CacheableTypes.Contains(cp.ContentType) && _cacheManager.GetCachedVersion(cp) == null)
        _cacheManager.DownloadToCache(cp);
}
catch (Exception ex)
{
    MessageBox.Show(
        "There was an error caching the content, content could not be started:\n\n" + ex.Message, "Error",
        MessageBoxButton.OK, MessageBoxImage.Error);
    return;
}

StartContent?.Invoke(this, cp);

 

The relevant portion of the external event handler is as follows:

 

Family fam;
using (var t = new Transaction(app.ActiveUIDocument.Document, "Load Family"))
{
    if (t.Start() != TransactionStatus.Started)
        throw new Exception("The transaction failed to start, could not load family.");

    app.ActiveUIDocument.Document
       .LoadFamily(ContentUtility.GetLocalCacheLocation(ExecutingContent, true), out fam);

    t.Commit();
}

if (fam != null)
{
    var symbol =
        (FamilySymbol) app.ActiveUIDocument.Document.GetElement(fam.GetFamilySymbolIds()
            .FirstOrDefault());
    if (symbol != null) app.ActiveUIDocument.PostRequestForElementTypePlacement(symbol);
}

 

As I said, all of this seems to work, but the dialog just goes dead afterward.  I also confirmed that it's only on upgrade.  If you perform the same tasks on a family that is in the current Revit version the upgrade does not happen and the dialog stays responsive and updates, etc.

 

Any advice is much appreciated.

0 Likes
609 Views
1 Reply
Reply (1)
Message 2 of 2

RPTHOMAS108
Mentor
Mentor

There is a lot going on outside of what is seen in the code given e.g. the updating of the window. Likely you'll have to replicate the issue in a minimum reproducible case.

 

The only thing I can note is you should be using UIApplication.MainWindowHandle not Process.MainWindowHandle.

 

"Returns the main window handle of the Revit application. This handle should be used when displaying modal dialogs and message windows to insure that they are properly parented. This property replaces System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle property, which is no longer a reliable method of retrieving the main window handle starting with Revit 2019."

 

I think where they say modal they mean modeless perhaps (since you can't set the parent of a modal window). Also I'm being pedantic now but I'm sure they mean 'ensure' not 'insure'.

0 Likes