In this article:
Starting and Displaying Fore.NET Form
Article number: KB000021
This article is used to introduce application developers to functionalities and features of using Fore.NET in Foresight Analytics Platform. It is also recommended to study the following:
NOTE. The development by means of the Fore.NET language, as well as the Fore language, must be executed in the test schema. Test and production repository are synchronized by means of update manager.
The first and fundamental difference of Fore.NET and Fore is that Fore.NET is enclosed in the .NET assembly object, that is, Fore.NET units and Fore.NET can be created and used only within Fore.NET assemblies.
Consider a simple example. Open integrated development environment in the project navigator and create a Fore.NET assembly. As a result, two objects are created: a Fore.NET assembly itself and a Fore.NET unit "Program" with the following code:
Imports System;
Public Class StartParams
Private m_Metabase: Prognoz.Platform.Interop.Metabase.IMetabase;
Public Property Metabase: Prognoz.Platform.Interop.Metabase.IMetabase
Get
Begin
Return m_Metabase
End Get
Set
Begin
m_Metabase := Value;
End Set
End Property Metabase;
End Class;
Public Class Program
[STAThread]
Public Shared Sub Main(Params: StartParams);
Begin
End Sub;
End Class;
This differs from the situation in Fore.
Introduce a definition:
An entry point in the Fore.NET language is a published static method Main of the Program class of the <Identifier of the started .NET assembly> namespace.
An entry point has a parameter of the StartParams type which contains a link to the current repository. This link is used instead of the MetabaseClass.Active method which is unavailable in Fore.NET as COM does not contain static methods and properties. Note that when a Fore.NET assembly is created, a link to the Metabase assembly is automatically added to the list of links.
Fore.NET has several types of assemblies: EXE, DLL. EXE in its turn is divided into WindowsApplication and ConsoleApplication. The DLL type is assigned to the Fore.NET assembly by default when it is created, which enables the user to run it in the object navigator in the current process of Foresight Analytics Platform, and connect this Fore.NET assembly to other Fore.NET assemblies using links.
Unlike a simple Fore assembly, a Fore.NET assembly can be started in the object navigator (context menu option: Open), entry point of the assembly is called.
Like in Fore, a Fore.NET assembly can be started for debugging from the development environment. Debugging is also executed in a separate platform process. Startup speed is the same as in Fore.
Unlike in Fore, you need to write additional code to start a newly created empty Fore.NET form.
See the following example of a created Fore.NET form:
Imports System;
Imports System.Collections.Generic;
Imports System.ComponentModel;
Imports System.Data;
Imports System.Drawing;
Imports System.Text;
Imports System.Windows.Forms;
Imports Prognoz.Platform.Forms.Net;
Namespace <Assembly_Identifier>
Public Partial Class <Form_Object_Identifier>Form: Prognoz.Platform.Forms.Net.ForeNetForm
Public Constructor <Form Object Identifier>Form();
Begin
InitializeComponent;
End Constructor;
End Class;
End Namespace;
A constructor without parameters is generated for the form, in which the InitializeComponent method is called. Going to the definition of this method opens another unit with the following code:
Imports System;
Imports System.Collections.Generic;
Imports System.ComponentModel;
Imports System.Data;
Imports System.Drawing;
Imports System.Text;
Imports System.Windows.Forms;
Imports Prognoz.Platform.Forms.Net;
Namespace <Assembly_Identifier>
Public Partial Class <Form_Object_Identifier>Form: Prognoz.Platform.Forms.Net.ForeNetForm
Private components: System.ComponentModel.IContainer = null;
Protected Override Sub Dispose(disposing: boolean);
Begin
If (disposing And (components <> null)) then
components.Dispose();
End If;
Inherited Dispose(disposing);
End Sub;
Private Sub InitializeComponent();
Begin
Self.components := New Container();
Self.Text := "<Form_Name>";
Self.Font := New System.Drawing.Font("Microsoft Sans Serif", 8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((204) As Byte));
Self.ResumeLayout(False);
End Sub;
End Class;
End Namespace;
You can see that a form with all its components is actually created in the InitializeComponent method. This gives a more clear idea of the moment when the form components are created.
This unit (<Form_Name>.Designer) is the form's design: it stores the components positioned on the form, their style and settings, and so on. This unit is included into the Fore.NET assembly as well as other units and forms but its contents is generated automatically by the form designer.
When creating a Fore.NET form, two classes with the same names are defined: <Form_Object_Identifier>Form. One of them is included into the designer unit, another is in the form unit. This is actually one and the same class, this possibility is provided by the Partial keyword included into the definition of form class (for further information on partial classes see Specification of the Fore.NET Language).
The Fore.NET assemblies work as follows: the assembly itself is started and not its individual units and forms that is why to start a form, create it and display in the entry point of the Fore.NET assembly:
Public Shared Sub Main(Params: StartParams);
Var
Forma: <Form_Object_Identifier>Form = New <Form_Object_Identifier> Form() = [<Form_Object_Identifier> Form];
Begin
Forma.Metabase := Params.Metabase;
Forma.Show(); // or Forma.ShowDialog();
End Sub;
This code creates a form object, then fills in the Metabase property for this object and displays it on the screen. Thus, the Metabase property of the ForeNetForm basic class is used within the form code instead of MetabaseClass.Active.
Single .NET assembly units may contain several implementations of entry points; the point which will be executed on .NET assembly startup is specified in assembly parameters. Some form can also be specified as a .NET assembly startup object, in this case entry points are ignored.
A .NET form can be opened modally relative to another .NET form by using the ShowDialog method. Modal forms are always shown in front of their parent forms. On working with a modal form consider the following: on closing a modal form its resources are not deleted, the form is only hidden. The form can be reopened by calling the ShowDialog method. To delete modal form resources, force call the Dispose method or use the Using operator on initializing the modal form:
Public Partial Class TESTForm: Prognoz.Platform.Forms.Net.ForeNetForm
Public Constructor TESTForm();
Begin
InitializeComponent();
End Constructor;
about: ForeNetForm;
Public Sub ShowModalForm();
Begin
about := New CustomDialogForm();
about.ShowDialog();
End Sub;
Public Sub ShowModalForm1();
Begin
Using about := New CustomDialogForm() Do
about.ShowDialog();
End Using;
End Sub;
Public Sub ShowModalForm2();
Begin
about := New CustomDialogForm();
about.ShowDialog();
about.Dispose();
End Sub;
Public Sub ReuseModalForm();
Begin
If (about <> Null) And (Not about.IsDisposed) Then
about.ShowDialog();
End If;
End Sub;
End Class;
The ShowModalForm, ShowModalForm1 and ShowModalForm2 methods open a modal window. If the window is opened by calling the ShowModalForm method, all resources remain in the computer memory after closing the window. The window can be reopened by calling the ReuseModalForm method. If the window is opened by calling the ShowModalForm1 or ShowModalForm2 methods, all resources are released after closing the window.
Fore.Net enables the use of standard .NET components (everything included into the System.Windows.Forms namespace). Fore.NET enables the use of components used in Fore. They are located on the Data Access and Common Controls tabs in the Components Panel window. These components are defined in the Forms.Net system assembly. You can work them as in Fore, though there are some features.
Consider the RdsDictionaryBoxNet component as an example. The following properties are defined in this component: Columns, CanElementLevelUp, CanElementDown, CanElementUp, FocusedElement, Source, UiSource, CtrlBox. All properties except for UiSource and CtrlBox are used in the standard Fore component RdsDictionaryBox. The events match as well. Let us consider the new properties:
UiSource. A link to the data source: UiRdsDictionaryNet.
CtrlBox. A link to the IRdsDictionaryBox object that is embedded into RdsDictionaryBoxNet to be displayed on a Fore.NET form. This property gives access to all methods and properties of the IRdsDictionaryBox COM interface including properties that are hidden for Fore. So you should use this link with care.
Errors (Exceptions) in Fore.NET can be divided into two types:
User errors. For example, NullReferenceException, InavalidCastException and other that are handled in a standard way and displayed as follows:
Object reference is not set to an object instance.
Error class: NullReferenceException
___________________________________
Calls stack:
in OBJ18283.Program.kuku() in OBJ18284:row 32
in OBJ18283.OBJ18762Form.test() in OBJ18761:row 23
Errors generated by methods and properties of classes and interfaces of the Foresight Analytics Platform kernel. Currently, the following error message is displayed:
An error in the HRESULTE_FAIL format is returned as the result of calling a COM component
If you have received this error text, you should add a defect with an example.
Fore.NET assemblies can be used to store external .NET assemblies. For example, ready-made classes and components written in C# (or another .NET compatible language) can be copied into a Fore.NET assembly, and then you can use this assembly through a link in other Fore.NET assemblies.
Use the IForeNetAssembly.LoadExternal(FileName: String) method to load an external assembly into the Fore.NET Assembly object of the repository:
Sub Test;
Var Asm: IForeNETAssembly; //type for .NET assembly , defined in the ForeNet system assembly
Begin
Asm := MetabaseClass.Active.ItemById(<Identifier_Of_Created_NET-assembly>).Edit As IForeNETAssembly;
Asm.IsExternal := True;
Asm.LoadExternal(<Path_To_External_Assembly>);
If Asm.AssemblyTarget <> 1 Then
Asm.AssemblyTarget := 1; // set assembly type dll
End If;
(Asm As IMetabaseObject).Save;
End Sub Test;
To use types defined in a Fore.NET assembly (external or standard), you need to connect the Fore.NET assembly using a link and use the following interfaces and types:
ForeNETAssemblyClass, IForeNetAssembly, IForeNetAssemblyRuntime, IForeNetForm, IForeNetRuntimeType, and so on.
For example, there is a class written in Fore.NET and saved in a .NET assembly:
Imports System;
Imports System.Windows.Forms;
Public Class Foo
Public Sub Test();
Begin
MessageBox.Show("Fore.NET method");
End Sub;
End Class;
Consider an example of calling the Test method from Fore:
Sub Button1OnClick(Sender: Object; Args: IMouseEventArgs);
Var run: IForeNETRuntime;
asm: IForeNETRuntimeAssembly;
typeFoo: IForeNETRuntimeType;
obj: IForeNETRuntimeObjectInstance;
res: Variant;
Begin
run := ForeNETAssemblyClass.Runtime; //Get Runtime where net code is to be executed
asm := run.Assembly(MetabaseClass.Active.ItemById("<NET-assembly_Identifier>").Bind As IForeNETAssembly); // Get compiled .NET assembly
typeFoo := asm.Type("<NET assembly_Identifier>.Foo"); //Obtain class Foo
obj := typeFoo.CreateInstance; //Create object of the Foo class
res := typeFoo.InvokeMethod("Test", obj, New Variant[0]); //Call method of this class
End Sub Button1OnClick;
To use the types defined in Fore units and forms in Fore.NET, connect the Fore assembly and use the following interfaces and types:
IForeClass, IForeObject, IForeAssembly, IForeSub, and so on.
For example, there is a class and method written in Fore:
Public Class Foo: Object
Public Constructor CreateEx(X: Integer; Y: Integer);
Begin
End Constructor CreateEx;
Public Sub Test;
Begin
WinApplication.InformationBox("Fore method");
End Sub Test;
Public Sub TestWithParams(X: Integer; Y: Integer);
Begin
WinApplication.InformationBox("Fore method with parameters");
End Sub TestWithParams;
End Class Foo;
Consider an example of calling two methods via Fore.NET:
Imports System;
Imports Prognoz.Platform.Interop.Metabase;
Imports Prognoz.Platform.Interop.Fore;
Public Class Program
//Call the Test procedure
Private Shared Sub InvokeMethod(mb: IMetabase);
Var
svc: IForeServices;
rnt: IForeRuntime;
assm: IForeAssembly;
ifs: IForeSub;
ifc: IForeClass;
ifo: IForeObject;
result: object;
Begin
svc := Mb As IForeServices; //Get object for work with Fore
rnt := svc.GetRuntime(); //Get Runtime, in which Fore methods will be executed
rnt.LoadAssembly("<Fore_Unit_Identifier>"); //Load Fore unit
assm := rnt.BindToAssembly("<Fore_unit_identifier>"); //Get compiled assembly
ifc := assm.BindToClass("Foo "); //Get Fore class
ifo := ifc.CreateObject(); //Create object of the Foo class
ifs := ifc.BindToMethod("Test"); //Get method of this class
ifs.Self := ifo; //Specify object
ifs.Invoke(); //Call Fore method
End Sub;
//Call the TestWithParams function with passing values of two parameters
Private Shared Sub InvokeMethodWithParams(MB: IMetabase; x: integer; y: integer);
Var
svc: IForeServices;
rnt: IForeRuntime;
assm: IForeAssembly;
ifconst, ifs: IForeSub;
ifc: IForeClass;
ifo: IForeObject;
result: object;
Begin
svc := Mb As IForeServices; //Get object for work with Fore
rnt := svc.GetRuntime(); //Get Runtime, in which Fore methods will be executed
rnt.LoadAssembly("<Fore_Unit_Identifier>"); //Load Fore unit
assm := rnt.BindToAssembly("<Fore_unit_identifier>"); //Get compiled assembly
ifc := assm.BindToClass("Foo "); //Get Fore class
ifo := ifc.CreateObject(); //Create object of the Foo class
//Constructor
ifconst := ifc.BindToMethod("CreateEx");
ifconst.Self := ifo;
ifsconst.Params.Item(0).Value := -1; //Specify the first parameter
ifsconst.Params.Item(1).Value := -1; //Specify the second parameter
ifconst.Invoke();
//Method
ifs := ifc.BindToMethod("TestWithParams"); //Get method of this class
ifs.Params.Item(0).Value := x; //Specify the first parameter
ifs.Params.Item(1).Value := y; //Specify the second parameter
ifs.Self := ifo; //Specify object
ifs.Invoke(); //Call Fore method
result := ifs.ResultValue; //Get execution result
End Sub;
[STAThread]
Public Shared Sub Main(Params: StartParams);
Begin
InvokeMethod(Params.Metabase);
InvokeMethodWithParams(Params.Metabase, 1, 100);
End Sub;
End Class;
There is no direct access (early binding) between Fore and Fore.NET. Therefore, you cannot connect Fore and Fore.NET assemblies to each other using a link and use types defined in these assemblies on the compilation stage.
See also:
Developers Knowledge Base | Integrated Development Environment | Components of .NET Form Designer | Early and Late Bindong