Documentation

Using custom code in building blocks

There are several things you can do within building blocks with custom code. The basic idea behind custom code in Axisbase is to leverage the Axisbase functionality rather than re-writing an entire application in custom code. This page describes how to plug custom code into building blocks that are used in the Axisbase client.

Please download the sample database with external code from www.divergentlabs.org (go to Downloads area). In the rest of this page, "sample database" refers to this database, and "sample code" refers to the code that is included with that download.

Code blocks

All c# code is in code building blocks. From the Building blocks window, choose Create>Code. Code building blocks are referenced from several other types of building blocks that allow customization, namely data outsources, bulk operations, display types, and user-defined building blocks. Code building blocks don't do anything by themselves; they are just points of reference for custom code.

You have two options for how to include code in a database: Link to assembly, or paste in source code. You only use one of these two methods, not both, for a particular code building block.

  • Linking: You can create an assembly (dll file) in Visual Studio. You can then copy the assembly to the same directory where the database file is, or keep it in some other directory. In the entry "DLL path and file name", if you just enter the file name with no path, it will look in the same directory as the database. You can enter a path relative to the database, or an absolute path. In the "Seach paths" field, enter the paths for any dependent assemblies - that is, assemblies that your assembly uses.

  • Pasting: Alternately, you can compile and test a class in Visual Studio, then copy the source code of the entire class into the code building block. In this case, Axisbase will compile the code each time you open the database.

Generally speaking, the source code method should be used for small bits of code, and saves you the trouble of the extra assembly file. If your external code is long or has multiple classes, use the external assembly.

Outsource from code

When you have a situation where you want custom code to create data or get it from a custom source, you can hook up a data outsource building block to a code building block. You can use the results of the data outsource in a list, report, bulk operation, or data subset. You can even use a data subset to combine data from a custom outsource with data from within the database.

With this functionality, Axisbase can be used to view lists, print mailing labels, or print reports from any source.

In the sample database, the list "show data from code" demonstrates this feature. Let's walk through each feature starting from the custom code:

  • The class KLoader contains a public static method Load(string name), which returns an instance of AxDataSet. In the sample, the method creates a table with one column and two rows, but yours could create any arbitrary data set. If your code needed to produce different data sets for different situations, you could create methods with different names and/or use the name argument to specify which set to produce.

  • The class KLoader is compiled into the assembly Axis1.SampleCode, which is copied to the same directory as the database.

  • The assembly Axis1.SampleCode is referenced by the code building block "samplecode". (Open the code block and press Test to make sure Axisbase can link to your external assembly.)

  • The data outsource building block "outsource from code" references the "samplecode" block on the Code tab. The class name and method are also listed here - in this case, KLoader.Load. (Press Test Import from Code to make sure Axisbase can find the method that you wrote.)

  • The list "show data from code" uses "outsource from code" as its data source. View the results of this list to see how the dataset produced by custom code can be shown in a list.

The class AxDataSet derives from DataSet. If you follow the example in Axis1.SampleCode, you can create an AxDataSet and AxDataTable as shown in that example. If you obtain a System.Data.DataSet from some other source, such as another database, you can then create an AxDataSet and use DataSet.Merge to copy the rows from your System.Data.DataSet into the AxDataSet.

User defined bulk operation step

When you have a situation where you have a data set, and you want to do some custom processing with it that Axisbase doesn't support, you can create a user-defined process step inside a bulk operation building block, and link that step to custom code.

In the sample database, the bulk operation "bulk op with code" demonstrates this feature. Let's walk through each feature starting from the custom code:

  • The class KWorker contains a public static method DoStep(...), which performs the actions on an instance of AxDataSet. In the sample, the method changes the price column, but yours could perform any arbitrary actions to the rows, or add or delete rows.

  • The class KWorker is compiled into the assembly Axis1.SampleCode, which is copied to the same directory as the database.

  • The assembly Axis1.SampleCode is referenced by the code building block "samplecode". (Open the code block and press Test to make sure Axisbase can link to your external assembly.)

  • The bulk operation "bulk op with code" includes a user defined step, created by pressing "Add user-defined". The step references the code block "samplecode" and lists the class and method to call - in this case, KWorker.DoStep.

  • When you press "Run All Steps" you see that the products listed have changed prices. In a real application, you would probably export or save the changes.

User defined display type

When you have a situation where you want to display a custom control to edit and display a cell within a list, you can create a user defined display type for this purpose. How you might use this is up to your imagination; the main limitation to keep in mind is that the underlying data type must be one of the built in types. You are only able to change the way the value is displayed and edited.

In the sample database, the list "use custom display type" demonstrates this feature, by showing an integer value as a horizontal bar, and using a scrollbar control for editing the value. Let's walk through each feature starting from the custom code:

  • The class SliderPainter derives from Axis1.Forms.DataCellPainter, and overrides several methods. The implementation must have a constructor with the same arguments as the sample, and it must override Control, ShowControl, PopulateControl, SaveValue, and Paint. The sample code has comments explaining each of these.

  • The class SliderPainter is compiled into the assembly Axis1.SampleCode, which is copied to the same directory as the database.

  • The assembly Axis1.SampleCode is referenced by the code building block "samplecode". (Open the code block and press Test to make sure Axisbase can link to your external assembly.)

  • The list "use custom display type" contains a cell showing the value from IRIS.task.percentcomplete. To see this, open "use custom display type" from the Building Blocks window, and go to the Layout tab. Click on IRIS.task.percentcomplete, then press Enter to open the cell. In the sample database, the checkbox "override display type" is checked, the editing mode is set to "User-defined code", the code block is set to "samplecode", and the class name is set to "SliderPainter".

Note that you could define the display type at the database level, rather than within the list building block. To do this, go to the database Properties window, Display Types tab. Create the custom display type there. Then go to the Record Types tab, open the type "task", and open the property "percentcomplete". In the property definition window, select the display type you just created. Once you do this, then ever list that shows the percentcomplete property will use the custom display type by default.

User defined window

When you have a situation where you need a completely custom window to be shown within Axisbase, use a user-defined building block invoked in its own window. This is a very open-ended way to plug in functionality. Your window can contain any controls and do virtually anything.

In the sample database, the block "graph" demonstrates this feature, by showing a graph using the external code library ZedGraph, based on data in the database. Let's walk through each feature starting from the custom code:

  • The class GraphForm derives from Axis1.Forms.NutFormBase, and overrides the method Execute. The sample code has comments explaining the arguments and required call to base.Execute.

  • The class GraphForm is compiled into the assembly Axis1.SampleCode, which is copied to the same directory as the database.

  • The assembly Axis1.SampleCode is referenced by the code building block "samplecode". (Open the code block and press Test to make sure Axisbase can link to your external assembly.)

  • The user-defined building block "graph" references the code block "samplecode" and also lists the Window class Axis1.SampleCode.GraphForm. (The Cell class entry is ignored when you are using the user-defined building block as a stand-alone window.) In this sample, the Data source is filled in, and that causes Axisbase to load the data identified by the data source, and pass it along to your custom window. If your window does not require data from Axisbase, you can leave the Data source entry undefined.

User defined cell

When you have a situation where you need custom control over painting a single cell within a list or window, use a user-defined building block invoked as a cell. This is the most complicated of all the ways of using external code. It has some points in common with the user-defined window (above).

You can use this to embed custom interactive controls within windows, or paint arbitrary images or graphs within lists. You can also paint based on detail data, so that within a list, the image displayed for each master row is based on the child rows related to that master row.

There are three separate contexts that a user-defined cell may be used, and you can choose to implement any one of these, or all three. The three contexts are (1) a top-level interactive control, such as in a window building block; (2) a top-level painted image, with no interaction; and (3) a painted image nested in a list.

In the sample database, the block "graph" demonstrates all three contexts, by showing a graph using the external code library ZedGraph, based on data in the database. Let's walk through each feature starting from the custom code:

  • The class GraphCellController derives from Axis1.Forms.CellController, provides a constructor, and overrides several methods. The sample code has comments explaining each method.

  • The class GraphCellController is compiled into the assembly Axis1.SampleCode, which is copied to the same directory as the database.

  • The assembly Axis1.SampleCode is referenced by the code building block "samplecode". (Open the code block and press Test to make sure Axisbase can link to your external assembly.)

  • The user-defined building block "graph" references the code block "samplecode" and also lists the Cell class Axis1.SampleCode.GraphCellController. (The Window class entry is ignored when you are using the user-defined building block as a cell.) In this sample, the Data source is filled in, and that causes Axisbase to load the data identified by the data source, and pass it along to your custom code.

Now let's examine how this actually works in each of the three contexts:

  • The window block "window with graph" is a window that contains the user-defined building block as a cell. To include a user-defined building block in a cell, choose Insert>Nested Building Block from the context menu, then choose the existing block. When the custom code constructor is invoked, it detects that the owning object is SlateNut (which is a window), so it sets the boolean flag interactive=true. When ShowControl is invoked, the code places the instance of ZedGraph on the parent control in the correct place. At this point the user can interact with the ZedGraph control from Axisbase.

  • The report block "report with one graph" is done almost the same way as "window with graph". However, since it is a report, which is non-interactive, the custom code does not place a Control instance on the parent, and instead the paintContents method is called to paint the graph.

  • The list block "show completion by dept" shows graphs that paint detail data. Note that the list is based on the data source "load dept/task" which loads a master/detail data set. In this data set, each department has a number of tasks associated with it. In the list, there are two columns: the department name, and a graph showing the completion of each task within that department. In the Layout tab of the list, a cell has been created with the user-defined block "graph". To include a user-defined building block in a cell, choose Insert>Nested Building Block from the context menu, then choose the existing block. When the custom code constructor is invoked, it detects the nested context and sets the boolean flag isNested=true. Then, on each call to paintContents, the code obtains the child rows (tasks) related to the master row (department), and builds the graph with that array of data rows.

(c) 2014-2015 Divergent Labs, Inc.