Skip to content

Commit 5a7b4e2

Browse files
Implement ability to run applications from the Loaded Applications tab
This change adds support for executing the OnStartup logic of IExternalApplication plugins directly from the Add-In Manager UI. Key changes: - Capture and store UIControlledApplication in App.cs. - Add RunActiveApp logic to AddinManagerBase.cs for both pre-R25 and R25+ versions. - Update AddInManagerViewModel to enable the Run button and handle application execution. - Add double-click command support for applications in FrmAddInManager.xaml. Co-authored-by: chuongmep <31106432+chuongmep@users.noreply.github.com>
1 parent abc7dd3 commit 5a7b4e2

4 files changed

Lines changed: 165 additions & 37 deletions

File tree

AddInManager/App.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public class App : IExternalApplication
2020
public static FrmAddInManager FrmAddInManager { get; set; }
2121
public static LogControl FrmLogControl { get; set; }
2222
public static FrmDockablePanel DockPanelProvider;
23+
public static UIControlledApplication UIControlledApplication { get; set; }
2324
public static int ThemId { get; set; } = -1;
2425
public static DockablePaneId PaneId => new DockablePaneId(new Guid("942D8578-7F25-4DC3-8BD8-585C1DBD3614"));
2526
public static string PaneName => "Debug/Trace Output";
@@ -34,6 +35,7 @@ public class App : IExternalApplication
3435

3536
public Result OnStartup(UIControlledApplication application)
3637
{
38+
UIControlledApplication = application;
3739
#if !(R25 || R26 || R27)
3840
AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
3941
#endif

AddInManager/Command/AddinManagerBase.cs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,49 @@ public Result RunActiveCommand(AddInManagerViewModel vm, ExternalCommandData dat
8888
return result;
8989
}
9090

91+
public Result RunActiveApp(AddInManagerViewModel vm, UIControlledApplication application)
92+
{
93+
var filePath = _activeApp.FilePath;
94+
if (!File.Exists(filePath))
95+
{
96+
MessageBox.Show("File not found: " + filePath, DefaultSetting.AppName, MessageBoxButton.OK, MessageBoxImage.Error);
97+
return Result.Failed;
98+
}
99+
Result result;
100+
try
101+
{
102+
vm.AssemLoader.HookAssemblyResolve();
103+
var assembly = vm.AssemLoader.LoadAddinsToTempFolder(filePath, false);
104+
if (null == assembly)
105+
{
106+
result = Result.Failed;
107+
}
108+
else
109+
{
110+
_activeTempFolder = vm.AssemLoader.TempFolder;
111+
if (assembly.CreateInstance(_activeAppItem.FullClassName) is not IExternalApplication externalApp)
112+
{
113+
result = Result.Failed;
114+
}
115+
else
116+
{
117+
result = externalApp.OnStartup(application);
118+
}
119+
}
120+
}
121+
catch (Exception ex)
122+
{
123+
MessageBox.Show(ex.ToString());
124+
result = Result.Failed;
125+
}
126+
finally
127+
{
128+
vm.AssemLoader.UnhookAssemblyResolve();
129+
vm.AssemLoader.CopyGeneratedFilesBack();
130+
}
131+
return result;
132+
}
133+
91134
#if R25 || R26 || R27
92135
public Result RunActiveCommand(ExternalCommandData data, ref string message, ElementSet elements)
93136
{
@@ -131,6 +174,48 @@ public Result RunActiveCommand(ExternalCommandData data, ref string message, Ele
131174
return result;
132175
}
133176

177+
public Result RunActiveApp(UIControlledApplication application)
178+
{
179+
var filePath = _activeApp.FilePath;
180+
if (!File.Exists(filePath))
181+
{
182+
MessageBox.Show("File not found: " + filePath, DefaultSetting.AppName, MessageBoxButton.OK, MessageBoxImage.Error);
183+
return Result.Failed;
184+
}
185+
Result result = Result.Failed;
186+
var alc = new AssemblyLoadContext(filePath);
187+
try
188+
{
189+
var assembly = Load(alc, filePath);
190+
var instance = assembly.CreateInstance(_activeAppItem.FullClassName);
191+
192+
if (instance is IExternalApplication externalApp)
193+
result = externalApp.OnStartup(application);
194+
}
195+
catch (Exception ex)
196+
{
197+
MessageBox.Show(ex.ToString());
198+
}
199+
finally
200+
{
201+
alc.Unload();
202+
203+
var alcWeakRef = new WeakReference(alc, trackResurrection: true);
204+
205+
Dispatcher.CurrentDispatcher.BeginInvoke(() =>
206+
{
207+
for (var counter = 0; alcWeakRef.IsAlive && counter < 10; counter++)
208+
{
209+
GC.Collect();
210+
GC.WaitForPendingFinalizers();
211+
}
212+
213+
Debug.WriteLine(alcWeakRef.IsAlive ? "Assembly has not been unloaded properly" : "Assembly unloaded");
214+
});
215+
}
216+
return result;
217+
}
218+
134219
private static Assembly Load(AssemblyLoadContext assemblyLoadContext, string filePath)
135220
{
136221
using var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);

AddInManager/View/FrmAddInManager.xaml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,6 @@
166166
x:Name="TreeViewApp"
167167
Grid.ColumnSpan="2"
168168
FontSize="12"
169-
ItemContainerStyle="{StaticResource TreeViewItemStyle}"
170169
ItemsSource="{Binding ApplicationItems, Mode=TwoWay}"
171170
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
172171
SelectedItem_="{Binding SelectedAppItem, Mode=TwoWay}"
@@ -190,6 +189,13 @@
190189
</StackPanel>
191190
</HierarchicalDataTemplate>
192191
</TreeView.ItemTemplate>
192+
<TreeView.ItemContainerStyle>
193+
<Style BasedOn="{StaticResource TreeViewItemStyle}" TargetType="{x:Type TreeViewItem}">
194+
<Setter Property="control:MouseDoubleClick.CommandParameter" Value="{Binding}" />
195+
<Setter Property="control:MouseDoubleClick.Command" Value="{Binding Path=DataContext.ExecuteAddinCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TreeView}}}" />
196+
<Setter Property="control:ExtendedTreeView.ContextMenuOpened" Value="{Binding ContextMenu.IsOpen, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TreeView}}}" />
197+
</Style>
198+
</TreeView.ItemContainerStyle>
193199
</control:ExtendedTreeView>
194200
</Grid>
195201
</TabItem>

AddInManager/ViewModel/AddInManagerViewModel.cs

Lines changed: 71 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -50,19 +50,22 @@ public AddinModel SelectedCommandItem
5050
{
5151
get
5252
{
53-
if (selectedCommandItem != null && selectedCommandItem.IsParentTree == true && IsTabCmdSelected)
54-
{
55-
IsCanRun = false;
56-
MAddinManagerBase.ActiveCmd = selectedCommandItem.Addin;
57-
}
58-
else if (selectedCommandItem != null && selectedCommandItem.IsParentTree == false && IsTabCmdSelected)
53+
if (IsTabCmdSelected)
5954
{
60-
IsCanRun = true;
61-
MAddinManagerBase.ActiveCmdItem = selectedCommandItem.AddinItem;
62-
MAddinManagerBase.ActiveCmd = selectedCommandItem.Addin;
63-
VendorDescription = MAddinManagerBase.ActiveCmdItem.Description;
55+
if (selectedCommandItem != null && selectedCommandItem.IsParentTree == true)
56+
{
57+
IsCanRun = false;
58+
MAddinManagerBase.ActiveCmd = selectedCommandItem.Addin;
59+
}
60+
else if (selectedCommandItem != null && selectedCommandItem.IsParentTree == false)
61+
{
62+
IsCanRun = true;
63+
MAddinManagerBase.ActiveCmdItem = selectedCommandItem.AddinItem;
64+
MAddinManagerBase.ActiveCmd = selectedCommandItem.Addin;
65+
VendorDescription = MAddinManagerBase.ActiveCmdItem.Description;
66+
}
67+
else IsCanRun = false;
6468
}
65-
else IsCanRun = false;
6669

6770
return selectedCommandItem;
6871
}
@@ -88,15 +91,21 @@ public AddinModel SelectedAppItem
8891
{
8992
get
9093
{
91-
if (selectedAppItem != null && selectedAppItem.IsParentTree == true && IsTabAppSelected)
92-
{
93-
MAddinManagerBase.ActiveApp = selectedAppItem.Addin;
94-
}
95-
else if (selectedAppItem != null && selectedAppItem.IsParentTree == false && IsTabAppSelected)
94+
if (IsTabAppSelected)
9695
{
97-
MAddinManagerBase.ActiveAppItem = selectedAppItem.AddinItem;
98-
MAddinManagerBase.ActiveApp = selectedAppItem.Addin;
99-
VendorDescription = MAddinManagerBase.ActiveAppItem.Description;
96+
if (selectedAppItem != null && selectedAppItem.IsParentTree == true)
97+
{
98+
IsCanRun = false;
99+
MAddinManagerBase.ActiveApp = selectedAppItem.Addin;
100+
}
101+
else if (selectedAppItem != null && selectedAppItem.IsParentTree == false)
102+
{
103+
IsCanRun = true;
104+
MAddinManagerBase.ActiveAppItem = selectedAppItem.AddinItem;
105+
MAddinManagerBase.ActiveApp = selectedAppItem.Addin;
106+
VendorDescription = MAddinManagerBase.ActiveAppItem.Description;
107+
}
108+
else IsCanRun = false;
100109
}
101110

102111
return selectedAppItem;
@@ -197,11 +206,7 @@ public bool IsTabCmdSelected
197206

198207
public bool IsTabAppSelected
199208
{
200-
get
201-
{
202-
if (isTabAppSelected) IsCanRun = false;
203-
return isTabAppSelected;
204-
}
209+
get => isTabAppSelected;
205210
set => OnPropertyChanged(ref isTabAppSelected, value);
206211
}
207212

@@ -339,17 +344,35 @@ public void ExecuteAddinCommandClick()
339344
{
340345
try
341346
{
342-
if (SelectedCommandItem?.IsParentTree == false)
347+
if (IsTabCmdSelected)
343348
{
344-
MAddinManagerBase.ActiveCmd = SelectedCommandItem.Addin;
345-
MAddinManagerBase.ActiveCmdItem = SelectedCommandItem.AddinItem;
346-
CheckCountSelected(CommandItems, out var result);
347-
if (result > 0)
349+
if (SelectedCommandItem?.IsParentTree == false)
348350
{
349-
App.FrmAddInManager.Close();
350-
RevitEvent.Run(Execute, false, null, false);
351+
MAddinManagerBase.ActiveCmd = SelectedCommandItem.Addin;
352+
MAddinManagerBase.ActiveCmdItem = SelectedCommandItem.AddinItem;
353+
CheckCountSelected(CommandItems, out var result);
354+
if (result > 0)
355+
{
356+
App.FrmAddInManager.Close();
357+
RevitEvent.Run(Execute, false, null, false);
358+
}
359+
}
360+
}
361+
else if (IsTabAppSelected)
362+
{
363+
if (SelectedAppItem?.IsParentTree == false)
364+
{
365+
MAddinManagerBase.ActiveApp = SelectedAppItem.Addin;
366+
MAddinManagerBase.ActiveAppItem = SelectedAppItem.AddinItem;
367+
CheckCountSelected(ApplicationItems, out var result);
368+
if (result > 0)
369+
{
370+
App.FrmAddInManager.Close();
371+
RevitEvent.Run(Execute, false, null, false);
372+
}
351373
}
352374
}
375+
353376
}
354377
catch (Exception e)
355378
{
@@ -360,11 +383,23 @@ public void ExecuteAddinCommandClick()
360383
private void Execute()
361384
{
362385
string message = Message;
363-
#if R19 || R20 || R21 || R22 || R23 || R24
364-
MAddinManagerBase.RunActiveCommand(this, ExternalCommandData, ref message, Elements);
365-
#else
366-
MAddinManagerBase.RunActiveCommand(ExternalCommandData, ref message, Elements);
367-
#endif
386+
if (IsTabCmdSelected)
387+
{
388+
#if R19 || R20 || R21 || R22 || R23 || R24
389+
MAddinManagerBase.RunActiveCommand(this, ExternalCommandData, ref message, Elements);
390+
#else
391+
MAddinManagerBase.RunActiveCommand(ExternalCommandData, ref message, Elements);
392+
#endif
393+
}
394+
else if (IsTabAppSelected)
395+
{
396+
#if R19 || R20 || R21 || R22 || R23 || R24
397+
MAddinManagerBase.RunActiveApp(this, App.UIControlledApplication);
398+
#else
399+
MAddinManagerBase.RunActiveApp(App.UIControlledApplication);
400+
#endif
401+
}
402+
368403
}
369404

370405
private void OpenLcAssemblyCommandClick()

0 commit comments

Comments
 (0)