The HOOPS/WPF integration consists of a connection between HOOPS/3dGS and the WPF Window and User Control GUI objects. This document describes how to use the HOOPS/WPF integration to build a .Net WPF application that incorporates the HOOPS/3dAF components. Some familiarity with .Net, Windows Presentation Format, HOOPS/3dGS and HOOPS/MVO is assumed.
Developers should start by compiling and running the basic wpf_simple application as the starting point for their application. This is the primary example for .Net WPF developers wishing to incorporate the HOOPS/3dAF components into either existing or new .Net applications. The readable source code is located in the <hoops>/demo/dotnet/wpf_simple directory.
The HOOPS/WPF integration is supported under Microsoft Visual Studio 2008 (VC9) running with .Net Framework 3.5. Developers running on Windows Vista Service Pack 1 will already have .Net Framework 3.5. If you are running on another Microsoft operating system, you may have to install .Net Framework 3.5 manually. You can download the package here.
The following steps are required to compile and run a HOOPS/WPF based application:
The above files are located in your <hoops>/bin/nt_i386_vc90 directory.
This section discusses the relationship between .Net WPF and HOOPS/3dAF components. Building an application with both these toolkits minimally involves using the following objects from each component.
A .Net WPF application typically has a Window object that contains controls displaying information from one document.
There should be at least one set of hoops_base::HPanel and hoops_base::HWindow objects, where the panel gets attached to the window. You usually create a custom panel and window derived from HPanel and HWindow. These two classes can be found in <hoops>/Dev_Tools/hoops_wpf/source/.
HBaseModel, HBaseView, an Operator class derive from HBaseOperator. Applications that want to implement selection of Geometry will also need a HSelectionSet object. These objects are all connected by private data members which store pointers to other objects in the following manner:
Programming with an object oriented GUI framwork like .Net WPF involves creating a set of objects and defining the ways in which they are connected, the manner in which they send and receive messages, and then launching the framework's event loop. Building an application using .Net WPF and HOOPS/3dAF specifically requires creation and initialization of:
A .Net WPF application usually creates a Application object which implements the function AppStartup(). The wpf_simple application does this in it's primary App.xaml.cs source file as follows:
public partial class App : Application { void AppStartup(object sender, StartupEventArgs args) { WPFSimpleWindow mainForm = new WPFSimpleWindow(); mainForm.Show(); } }
The HOOPS/WPF integration consists of a customized WPF Window and UserControl called HWindow and HPanel, as diagramed up above. (Again, the panel will get attached to the window.) As many pairs of these objects can be created as needed to implement the GUI's design. Your application should define custom HWindow and HPanel classes, as shown in wpf_simple source.
Custom SimpleWPFPanel definition taken from the wpf_simple project's SimpleWPFPanel.cs source file:
public partial class SimpleWPFPanel : HPanel { // Constructor which calls the Init() method of the class public SimpleWPFPanel(): base() { InitializeComponent(); } // This method will set up the default HOOPS/MVO view for the panel and attach a HOOPS/MVO default operator public void InitializeComponent() { // contents reviewed later } }
Here is custom WPFSimpleWindow definition taken from the wpf_simple project's SimpleHWindow.xaml.cs source file. Note that it creates the custom WPFSimpleWindow object and initializes the window:
public partial class WPFSimpleWindow : HWindow { ... // Sets up the panel and window private void Init() { //Checking to see if an instance of WindowsFormsHost has been created to host the panel if(is_host_added == 0) { m_pHPanel = new SimpleWPFPanel(); /********************************************************************************** /* To use the HOOPS/WPF Panel in your WPF application, it is critial that you * /* MUST assign the panel as a child of your instance of WindowsFormsHost. Then, * /* you MUST add the WindowsFormsHost to your application in the desired location.* ***********************************************************************************/ m_pWinFormsHost.Child = m_pHPanel; CanvasGrid.Children.Add(m_pWinFormsHost); is_host_added = 1; } // first set up the window, then set the axis triad options m_pHPanel.m_pHModel.Flush(); m_pHPanel.m_pHView.Update(); m_pHPanel.m_pHView.SetAxisMode(AxisMode.AxisOn); m_pHPanel.m_pHView.AdjustAxisWindow(); ... } ... }
Finally, we can note that the File->New and File->Open methods in WPFSimpleWindow will create a new custom WPFSimpleWindow object:
public partial class WPFSimpleWindow : HWindow { ... private void New_Click(object sender, RoutedEventArgs e) { WPFSimpleWindow newWindow = new WPFSimpleWindow(); newWindow.Init(); newWindow.Show(); } private void Open_Click(object sender, RoutedEventArgs e) { WPFSimpleWindow newWindow = new WPFSimpleWindow(); newWindow.Init(); newWindow.Load_File(sender, e); newWindow.Show(); } private void Load_File(object sender, RoutedEventArgs e) { //Creating the Open File Dialog openFileDialog = new OpenFileDialog(); openFileDialog.Title = "Load"; openFileDialog.Filter = "HMF/HSF files (*.hmf, *.hsf)|*.hmf;*.hsf" + "|All files (*.*)|*.*"; //Showing the File Dialog Nullable<bool> result = openFileDialog.ShowDialog(); if (result == true) { //Loading the file into the HOOPS Database m_pHPanel.m_pHModel.Flush(); m_pHPanel.m_pHModel.Read(openFileDialog.FileName); m_pHPanel.m_pHView.FitWorld(); // This resets the camera so that it views the extents of the scene m_pHPanel.m_pHView.Update(); } } ... }
One global pointer to a HOOPS/MVO HDB object should be declared and initialized in your application's main class. The wpf_simple app does this in the main WPFSimpleWindow constructor (located in SimpleHWindow.xaml.cs) :
public partial class WPFSimpleWindow : HWindow { .... // Constructor which initializes hoops database and GUI features of the main window */ public WPFSimpleWindow() { ... m_pHDB = new HDB(); m_pHDB.Init(); ... } }
Multiple HBaseModel objects can be created as needed. The wpf_simple app creates one for every SimpleWPFPanel object (i.e., there is a one-to-one mapping of HBaseModel to SimpleWPFPanel objects) and does so in the SimpleWPFPanel::InitializeComponent :
public partial class SimpleWPFPanel : HPanel { ... public void InitializeComponent() { ... m_pHModel = new HSimpleModel(); m_pHModel.Init(); ... } ... }
Multiple HBaseView objects can be created as needed, with one object usually being created for each SimpleWPFPanel. The HBaseView needs a valid native GUI window id passed to its constructor on object creation; this information is used to connect a HOOPS/3dGS output driver instance to a SimpleWPFPanel. This requires that the SimpleWPFPanel, to which the HBaseView will be attached, already exist prior to creating the HBaseView object.
Your app should create the HBaseView object in your overloaded SimpleWPFPanel::InitializeComponent method. Here is the wpf_simple example taken from SimpleHPanel.cs :
public partial class SimpleWPFPanel : HPanel { ... public void InitializeComponent() { ... m_pHView = new HSimpleView(m_pHModel, "?picture" + winid, "opengl", "", winid); m_pHView.Init(); ... } ... }
The HBaseView class and SimpleWPFPanel class contain pointers to a HSelectionSet object. A selection set class would typically be created and initialized during SimpleWPFPanel initialization. After creation, it's important to pass the HSelectionSet operator into HBaseView by calling HBaseView::SetSelection. The wpf_simple app does this in the overloaded method of SimpleWPFPanel::InitializeComponent method:
public partial class SimpleWPFPanel : HPanel { ... public void InitializeComponent() { ... // view and model initialization goes here, and was discussed previously // Set up the custom HSelectionSet object m_pHSelection = new HSimpleSelectionSet(m_pHView); m_pHView.SetSelection(m_pHSelection); m_pHView.GetSelection().Init(); ... } }
The HBaseView class and SimpleWPFPanel class contains pointers to a HBaseOperator object. A default operator would typically be created and initialized during SimpleWPFPanel initialization. After creating, you should set it to be the current operator by calling the utility method SimpleWPFPanel::SetCurrentOperator. The wpf_simple app does this in the overloaded method of SimpleWPFPanel::InitializeComponent method:
public partial class SimpleWPFPanel : HPanel { ... public void InitializeComponent() { ... // Set the default operator m_pHOperator = new HOpCameraManipulate(m_pHView); m_pHView.SetCurrentOperator((HBaseOperator)m_pHOperator); ... } }