Exploring the Smart Office Visual Tree – Figuring out the Field Names

If you are playing around with WebServices in LWS Designer and the M3 Business Engine, then you will have probably have had some fun trying to figure out which field to choose.

Now there are a couple of things that you can do, you can look at the view definitions (on our AS400 they are in ROOT\QIBM\UserData\mne_data \viewDefinitions\viewDef_1412S\)and dredge through the .xml file looking for something useful or you can take advantage of the Visual Tree. (see: http://msdn.microsoft.com/en-us/library/ms753391.aspx ). As I am interested in seeing how the panels are made up in WPF terms I decided to take a more programmatic approach – it also provides a better context when reading through the Lawson MForms Developers Guide. It also gives me an opportunity to practice programming in jscript and break Smart Office – yes, I killed it a couple of times when I ran my script repeatedly 🙂

So I wrote a function called displayChildren(), it will take an object and use the VisualTreeHelper class to find any children. We will then use reflection to get the “Name” property of the object and we’ll also display the type of object. And to boot, it’s indented depending on how deep within the Visual Tree you are.

So, I mucked around with BUS100 again.

It’s a nice simple program which is ideal to experiment with.

Based on experience with WPF, at a glance I can say that this will comprise of a Grid, Combobox, ListView and within the ListView header there is a StackPanel per column. Within the first columns StackPanel there is a Label and then a TextBox.

Fairly standard sort of stuff.

Now we can look at going up the Visual Tree to the top or we can just work on from the GridView downwards. You can use this code to go upwards and investigate lots of interesting things, but for the moment and for the interest of this discussion we’ll just look at the panel.

I use the panel as the seed passed to my function displayChildren(). As you can see we have a Label Field which is called WDI0115 which is collapsed, there is also a WWDIVI field which is also Collapsed.

We don’t see the Sorting Order by default because that is at a higher level, if you decide to go from the highest level then expect to get an OutOfMemoryException (Smart Office will ask you to restart). If there are a large number of objects things quickly go south.

1.3gig of RAM seems a tad excessive given we came from 78K 🙂

Interestingly the memory used doesn’t appear to be released back to the system until you close Smart Office (even when you only do from the Grid down).
Still, something to investigate further.

Anyways, here’s the code…

 

import System;
import System.Windows;
import System.Windows.Controls;
import System.Windows.Media;
import System.Windows.Media.Media3D;
import System.Reflection;
import MForms;

package MForms.JScript {
   class VTWalker {
      public function Init(element: Object, args: Object, controller : Object, debug : Object) 
      {
              // this is a grid that appears on our panel, interestingly it doesn't include some of the higher
              // level controls on the main panel
             var content : Object = controller.RenderEngine.Content;

            // to prove that we are indeed a Grid.
              debug.WriteLine("content object type = " + content.GetType().ToString());
              
              var parent : Object = content;
              var lastParent : Object = content;

              // here we will loop UP the VisualTree seeking the top
              while(null != (parent = VisualTreeHelper.GetParent(parent)))
              {
                  lastParent = parent;
              }
              debug.WriteLine(" ************ ");
              debug.WriteLine(" ************ ");
              debug.WriteLine("From Grid downwards");
              // output the tree from the Grid down, if you want to
              // go from the very highest Parent, then change content to lastParent
              displayChildren(content, 1, debug);
      }
      
      // displayChildren
      //  display information for each of the objects children
      //  recurse down the tree
      // parent - the object whose children we want to investigate
      // depth  - we keep track of the depth so we can indent our output to make reading easier
      // debug  - so we can output our data
      private function displayChildren(parent : Object, depth : int, debug : Object)
      {
              try
              {
                  if(null != parent)
                  {
                      // get the type of our object, we do this
                      // so we can check if the object inherits
                      // from a DependencyObject
                      var parentobjType : Type = parent.GetType();
                      if(parentobjType.IsSubclassOf(DependencyObject) == true)
                      {
                          // loop through the children of this object
                          for(var i=0; i < VisualTreeHelper.GetChildrenCount(parent);i++)
                          {
                              // retrieve the child object
                              var current : Object = VisualTreeHelper.GetChild(parent,i);
                              if(null != current)
                              {
                                  // here we shall deterine the type of the new object
                                  var objType = current.GetType();
                                  // we're looking for the Name property, because
                                  // this is what I am interested in
                                  var objPropertyInfo = objType.GetProperty("Name");
                                  var objPropertyVisible = objType.GetProperty("Visibility");
                                  
                                  // strPadding allows us to indent
                                  var strPadding : String = "";
                                  for(var j = 0; j < (depth * 4); j++)
                                  {
                                      strPadding += " ";
                                  }
                                  
                                  // if objPropertyInfo is null then
                                  // we couldn't find the Name property
                                  if(null != objPropertyInfo)
                                  {
                                      // output the name of the object
                                      debug.WriteLine(strPadding + "Object name: " + objPropertyInfo.GetValue(current));
                                  }
                                  else
                                  {
                                      debug.WriteLine(strPadding + "Object name: Unknown");
                                  }
                                  // output the objects type
                                  debug.WriteLine(strPadding + "Object Type: " + objType.ToString());
                                  
                                  if(null != objPropertyVisible)
                                  {
                                      debug.WriteLine(strPadding + "Object Visibility: " + objPropertyVisible.GetValue(current).ToString());
                                  }
                                  
                                  // does the current object have any children?
                                  if(VisualTreeHelper.GetChildrenCount(current) >= 1)
                                  {
                                      // recurse down
                                      displayChildren(current,depth+1, debug);
                                  }
                              }
                          }
                      }
                  }
              }
              catch(ex)
              {
                  debug.WriteLine("!-! Exception: " + ex.Message + " " + ex.StackTrace);
              }
      }
   }
}
This entry was posted in Development, How Far is Too Far?, M3 / MoveX. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s