Ok, so before you ask why on earth would you bother let me explain 🙂
As part of my work over at ClarionAddins I am always looking for way to improve the user experience as well as stretching my knowledge of .Net programming. I thought it might be nice to use WPF but since the Clarion IDE is targeting v2.0 of the .Net framework this is not so easy. Hence this example!
Of course there are many resources out there related to this topic, see below, but nothing I could discover specific to v2.0 so for me it took a little work to get there. I learnt a lot about reflection along the way!
- Walkthrough: Hosting a WPF Composite Control in Windows Forms
- WPF Tutorial – Using WPF In WinForms
- A XAML graphics viewer and validator for Windows Forms
This code assumes that the v3.5 Framework is installed on the target machine. For production it would of course be necessary to test for this and react accordingly.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
using System; using System.IO; using System.Reflection; using System.Windows.Forms; namespace ClarionAddins.WpfTest { public partial class WpfTestForm : Form { public WpfTestForm () { InitializeComponent(); AddWpfControl(); } private void AddWpfControl() { // You need a full AssemblyQualifiedName for the elementHost class string elementHostQualifiedName = "System.Windows.Forms.Integration.ElementHost, WindowsFormsIntegration, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"; // Using this it is possible to load the ElementHost class at runtime and create an instance we can use Type elemHostType = Type.GetType(elementHostQualifiedName, true); object ctrlHost = Activator.CreateInstance(elemHostType); // Dock this ElementHost into our WinForms control container MethodInfo info = elemHostType.GetMethod("Dock"); elemHostType.GetProperty("Dock").SetValue(ctrlHost, DockStyle.Fill, null); // Finally, add the ElementHost to the WinForms list of controls this.Controls.Add((Control)ctrlHost); // Now, load the WPF UserControl to be displayed string currentPath = Path.GetDirectoryName((new System.Uri(Assembly.GetExecutingAssembly().CodeBase)).AbsolutePath); string userControlPath = Path.Combine(currentPath, "WpfControlLibrary.dll"); Assembly assembly = Assembly.LoadFrom(userControlPath); Type userControlType = assembly.GetType("WpfControlLibrary.MyUserControl", true); // Create an instance of the UserControl and call the InitializeComponent method object userControl = Activator.CreateInstance(userControlType); info = userControlType.GetMethod("InitializeComponent"); info.Invoke(userControl, null); // Last of all, attach the UserControl to the ElementHost ! elemHostType.GetProperty("Child").SetValue(ctrlHost, userControl, null); } } } |
Here is a screenshot of this technique being used in an addin I am working on:
-brahn