As introduced previously, we can add a WPF User Control, do everything in the control to meet the UI needs such as control layouts, data bindings and event handlings, create a WPF window on the fly to host the user control, and launch it from inside an External Command of Revit Addins.
Of course, to make the host WPF Window and in turn the hosted child WPF User Control both look nice and behave good, something has to be done on the host WPF Window side as well, as demonstrated in the previous post of the WPF and Revit Addin/API article series.
Another way to show a WPF window in a Revit addin is apparently to create a WPF application first, turn it into a Class Library project next, and finally make it become a really Revit Addin project through either manually adding Revit relevant stuffs little by little or copying all those over from an existing Revit Addin project, created by the RevitAddinWizard automatically, for example. Either way, it is a tedious and error prone process.
Things always have two sides as we all know anyway. As discussed in an early article of the WPF and Revit Addin/API series, the WPF User Control approach has also its drawback. For instance, though the OK and Cancel buttons can be added into the user control as well, it is obvious that styling, sizing/resizing and contenting had better be done from the host window side, and that will lose the benefits of WYSIWYG.
Let us check on the second approach here, converting a WPF application to a Revit class library. Meanwhile, we will figure out a way to work around a limitation imposed by the Visual Studio IDE with no good reasons.
First, we create a WPF Application project and name it as WpfAppToRevitClass.
Next, we switch the Output type of the project from WPF Window Application to Class Library in the Project Properties window:
At this time, if the project is trying to be compiled, the following errors will be complained:
Error 1 Library project file cannot specify ApplicationDefinition element. C:\Windows\Microsoft.NET\Framework\v3.5\Microsoft.WinFX.targets 294 9 WpfAppToRevitClass
Error 2 The project file contains a property value that is not valid. C:\Windows\Microsoft.NET\Framework\v3.5\Microsoft.WinFX.targets 294 9 WpfAppToRevitClass
All these are stemmed from the same root, the WPF App.xmal is still taking part in the compiler activities. Changing its Build Action from the original ApplicationDefinition to None resolves the issues all together:
It may be a good idea to add a very simple button to the window as we did before:
<Window x:Class="WpfAppToRevitClass.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<Button Margin="22,109,12,127" Name="button1" Click="button1_Click">Convert WPF Application to Revit Class</Button>
</Grid>
</Window>
and implement its callback like:
private void button1_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Hello friends! I was successfully converted from a WPF Application!");
}
Now it is time to add those Revit Addin relevant stuffs into the project, e.g. ExtApp, ExtCmd, resources, buttons, panels, etc. It might be easier to copy these including the manifest file over from another Revit Addin project created by the RevitAddinWizard and rename everything, but please bear something quite subtle in mind: the ExtApp/ExtCmd namespaces and class names, command names of ribbon buttons, and embedded resource types for images.
Next to the last, we create the WPF window in the Execute() callback of the external command we care. If it is created by the RevitAddinWizard, the good place to put the code is below the TODO comment, like:
//TODO: add your code below.
Window1 wpfWin = new Window1();
if (wpfWin.ShowDialog() == false)
return Result.Cancelled;
Before building the addin project, we have to make one more little tweak. Due to the fact that the PresentationFramework assembly reference has been introduced into the project automatically by the WPF User Control item creation and its namespace System.Windows has the same MessageBox type now as the WinForm System.Windows.Forms, an error message reporting ambiguity will be generated for the simple MessageBox.Show() call.
After making the type fully qualified as:
System.Windows.Forms.MessageBox.Show
or better commenting out the Windows Forms namespace like the following to use the WPF version MessageBox instead:
//using System.Windows.Forms;
the project should compile and build well.
Last, we give the assembly a try. After Revit is launched, either from inside the Visual Studio IDE by pressing F5 or outside of it, one more ribbon panel will appear under the Add-Ins ribbon tab. Supposing the project is named as suggested, the new ribbon panel and button will look like the following:
If the ExtCmd button is clicked, a WPF window will show up, as we expected. And better, the window icon has been set as the default Revit TaskDialog one automatically:
If the button is pressed, the test addin will say hi and introduce itself a bit:
So, it proves the concept clearly, showing a WPF window in the addins of Revit 2011 and newer is not a problem at all. And many ways exist actually.
All in all, this is another way to show a WPF window from Revit Addins. There surely be some others, and maybe better. If readers have another one, welcome to point it out.
More articles about WPF and Revit Addin/API can be expected soon. Please stay tuned. RevitAddinWizard may provide a few coders to address some such common situations in the near future.
Recent Comments