We presented a programmatic way earlier to show a WPF window from within an External Command of a Revit Addin created by the Revit API.
Because of some barriers that the Visual Studio IDE imposes (without good and clear reasons), we could only create a User Control (WPF) in the Revit Addin project (a Class Library in the Visual Studio terminologies) without finding a backdoor. So we chose to create a User Control and do whatever possible inside it such as UI element layouts, event subscriptions, and so on, and host the user control into a WPF Window which was created on the fly.
However, as discussed in that post, some fine tuning work was apparently necessary for the WPF Window, e.g. adding two important buttons (OK and Cancel), sizing and resizing the host window and the hosted user control to make both look and behave good, hiding unnecessary icons, etc. Let us look into these in this article.
Before digging anything further, let us add some indicator controls to the user control:
The four small little tiny buttons are nothing but indicating the corners of the user control. This can exercise our eyes a little bit and rest our minds a lot. Certainly are there many other ways. It is just my personal choice.
We also add the OK and the Cancel buttons statically into the User Control, as recommended before, rather than dynamically into the host Window on the fly.
Two reasons I can think of at this moment:
1) Coding easy, we should avoid adding controls on the fly to the window if possible as it will bring up a lot of coding and calculation work;
2) Looking natural, it seems good to put all similar stuffs and drive them in the same central place.
Let us show what the Window hosting the User Control will look like if we create the window on the fly with the same code as we demonstrated before:
UserControl1 userControl = new UserControl1();
Window win = new Window();
win.Content = userControl;
win.Show();
The window looks so inappropriate:
No ideas of why the window has this size and how the user control is laid out or aligned by the window by default, but it is not good at all, we all know.
Ok, now the key role comes onto the stage, how to make the window and the control not only look good, the window and the control really become one, but also behave natural, clicking the OK closes the host window and returns a DialogResult.OK as in the WinForm world and clicking the Cancel closes the window too but returns a DialogResult.Cancel if possible.
We have to do quite something to make all these happen.
First, add the two buttons as demonstrated above.
Second, had better add some code to indicate what they are with some code like the following during the initialization of the user control:
public UserControl1()
{
InitializeComponent();
this.button_Cancel.IsCancel = true;
this.button_OK.IsDefault = true;
}
Third, implement the button callbacks as follows:
private void buttonOK_Click(object sender, RoutedEventArgs e)
{
(this.Parent as Window).DialogResult = true;
(this.Parent as Window).Close();
}
private void button_Cancel_Click(object sender, RoutedEventArgs e)
{
(this.Parent as Window).DialogResult = false;
(this.Parent as Window).Close();
}
The above look-simple but get-hard code is the core part one. Please note: the WPF Windows’ DialogResult property is not a enumerator anymore, instead, a boolean now. Why? Everybody wants to be different, I guess.
Fourth, create the host window as before:
private void button1_Click(object sender, EventArgs e)
{
UserControl1 userControl = new UserControl1();
Window win = new Window();
win.Content = userControl;
…
}
Fifth, adjust the created window as we like:
private void button1_Click(object sender, EventArgs e)
{
…
win.Width = win.Height = double.NaN;
win.SizeToContent = SizeToContent.WidthAndHeight;
win.ShowInTaskbar = win.Topmost = true;
win.ResizeMode = ResizeMode.NoResize;
win.WindowStartupLocation = WindowStartupLocation.CenterScreen;
win.HorizontalAlignment = win.HorizontalContentAlignment = System.Windows.HorizontalAlignment.Left;
win.VerticalAlignment = win.VerticalContentAlignment = VerticalAlignment.Top;
…
}
The core part two appears now. Besides the core of the core, the SizeToContent property of the WPF window, readers may also have noticed the double.NaN for the Window.Width and the Window.Height proprties.
What is that supposed to do? Doesn’t it generate an exception?
No, not all all. Some good and as expected result just comes out, setting the two dimensions as Auto adjusted. The value type of the Width and the Height is not changed to something different this time (a String seems a good candidate here). Rather, an unusual but compatible means is introduced.
All are good anyway, making things done at least.
Sixth, show the window as a dialog so that we have a chance to check its return value:
private void button1_Click(object sender, EventArgs e)
{
…
System.Windows.MessageBox.Show(string.Format("OKed? : {0}", win.ShowDialog()));
}
Last but not least, give it a try and have a look at its look and check the dialog results it could result in.
By the way, it is still only a start point for the task, looking from this perspective. If needed, these ideas and code can be extended to become a product/framework for sure. If readers are interested in doing so, please go ahead.
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