You will create a new Windows Form that will be used in place of the base form. This new form will display both the content from the Dexterity-based window, as well as the additional controls you are adding.
To add the new form, complete the following procedure:
From the Project menu, choose Add Windows Form.
In the Add New Item window, name the new Windows Form. Click Add.
In the Solution Explorer, right-click on the form and choose View Code to display the code for the new form.
Add a using statement to provide convenient access to the code in the Microsoft.Dexterity.Shell namespace.
using Microsoft.Dexterity.Shell;
By default, the class for the new form will inherit from the Form class. To be used as a form factory, it must inherit from the proper class in the Microsoft.Dexterity.Shell namespace. The inherited class depends on the window type of the Dexterity-based window for which the form factory is being created.
When you specify the inherited class from the Microsoft.Dexterity.Shell namespace, the Windows Form will be redrawn with window elements that match Microsoft Dynamics GP. |
For instance, the following C# code shows the Windows Form class that will be used for the About Box form in Microsoft Dynamics GP. Notice how the form class inherits from the DexTaskForm class. The default constructor is also shown.
namespace FormFactorySample { public partial class SampleForm : DexTaskForm { public SampleForm() { InitializeComponent(); } } }
Add an additional constructor to instantiate the form that will contain both the Dexterity-based window content, as well as your new controls. You will call this constructor from the form factory class. The set of parameters for the constructor depends on the type of form.
For forms that inherit from the DexTaskForm class, the new constructor must have the following parameters:
Parameter |
Type |
Description |
---|---|---|
name |
string |
The display name for the Dexterity window. |
windowType |
DexWindowType |
An enumeration that specifies the window type. The following values are possible: Lookup ModalDialog ModlessDialog Palette Primary Toolbar Wizard |
flags |
FormFlags |
A bitmask that specifies properties of the Dexterity window. The available flags are: TNTClose TNTDialog TNTHGrow TNTHScroll TNTResize TNTVGrow TNTVScroll |
windowState |
WindowState |
The initial appearance of the window. |
minClientSize |
System.Drawing.Size |
Minimum size that the Dexterity window can be reduced to. |
clientSize |
System.Drawing.Size |
The initial size that the Dexterity window will have. This value includes the standard window elements, such as the title bar. |
hResizeable |
bool |
Specifies whether the window can be resized horizontally. |
vResizeable |
bool |
Specifies whether the window can be resized vertically. |
productId |
short |
The dictionary ID of the product that defines the Dexterity-based window. |
formId |
short |
The form ID of the form resource that defines the Dexterity-based window. |
windowId |
short |
The window ID of the window resource that defines the Dexterity-based window. |
modified |
bool |
Indicates whether the form resource was retrieved from the forms dictionary for the product. |
For forms that inherit from the DexDialogForm class, the new constructor must have the following parameters:
Parameter |
Type |
Description |
---|---|---|
name |
string |
The display name for the Dexterity window. |
windowType |
DexWindowType |
An enumeration that specifies the window type. The following values are possible: Lookup ModalDialog ModlessDialog Palette Primary Toolbar Wizard |
flags |
FormFlags |
A bitmask that specifies properties of the Dexterity window. The available flags are: TNTClose TNTDialog TNTHGrow TNTHScroll TNTResize TNTVGrow TNTVScroll |
windowState |
WindowState |
The initial appearance of the window. |
minClientSize |
System.Drawing.Size |
Minimum size that the Dexterity window can be reduced to. |
productId |
short |
The dictionary ID of the product that defines the Dexterity-based window. |
formId |
short |
The form ID of the form resource that defines the Dexterity-based window. |
windowId |
short |
The window ID of the window resource that defines the Dexterity-based window. |
modified |
bool |
Indicates whether the form resource was retrieved from the forms dictionary for the product. |
Like the default constructor, the new constructor should call the InitializeComponent() method for the form.
As an example, the following C# code shows the additional constructor that will create the new Windows form to be used as the wrapper for the About Box window in Microsoft Dynamics GP.
public SampleForm(string name, DexWindowType windowType, FormFlags flags, WindowState windowState, System.Drawing.Size minClientSize, System.Drawing.Size clientSize, bool hResizeable, bool vResizeable, short productId, short formId, short windowId, bool modified) { InitializeComponent(); }
Use Visual Studio’s graphical form designer to create the layout for the new form. When you view the form in the designer, you will see that it contains a “content panel” control into which you will add your controls. This control is added automatically by the form class inherited from the Microsoft.Dexterity.Shell namespace.
The new form layout must provide a control that will host the content from the Dexterity-based window. It must also contain the additional controls you are adding to the form. One basic way to accomplish this is through the SplitContainer control, which is a standard .NET control. Drag this control out from the Toolbox into the content panel. The left panel of the split container will host the Dexterity-based window content. The right panel of the split container will host the new controls you are adding. The following illustration shows the new form after the split container control was added.
You could use any of the other layout controls, such as the TableLayoutPanel, when defining the form layout. Which you choose will depend on your layout needs.
The Dexterity runtime doesn’t know how large the new form with its additional controls will need to be to display properly. Code in your form factory must specify the size to accommodate the Dexterity-based content, as well as the new controls you have added. You must override the protected GetPreferredClientSize method to specify the size the new form will have. You are specifying the outside dimensions of the form, including the borders, title bar, etc. The value you return indicates the size the form will have.
The dexClientSize parameter passed in to this method contains the dimensions of the Dexterity-based content that the new form must host. You can also call the GetPreferredClientSize method from the form base class to get the outer dimensions of the base Dexterity window. Together, these values can be used to help you compute the size of the window.
The following example is the C# code that sets the size of the form that will display the About Box content, as well as some additional controls added for the form factory. The code is part of the class for the new form, located in the same class as the default constructor. It overrides the protected GetPreferredClientSize method. This example sets the total size of the window.
protected override Size GetPreferredClientSize(Size dexClientSize, DexWindowType windowType, short productId, short formId, short windowId, bool modified, bool apply) { Size baseClassSize; if (apply) { // Store the size of the About Box content area AboutBoxSize = dexClientSize; // Query the base class to get the outer dimensions of the Dexterity window baseClassSize = base.GetPreferredClientSize(dexClientSize, windowType, productId, formId, windowId, modified, apply); // Add width for the splitter and new control area baseClassSize.Width += (splitContainer1.SplitterWidth + 150); return baseClassSize; } else { return base.GetPreferredClientSize(dexClientSize, windowType, productId, formId, windowId, modified, apply); } }
The position of the splitter that divides the Dexterity-based window content from the .NET content must also be specified. This can be done in an override for the protected OnResize method for the base class. Typically, the position can be set to the width of the inner content area for the Dexterity-based window.
protected override void OnResize(EventArgs e) { // Call OnResize for the base class base.OnResize(e); // When the window is resized, set the position of the splitter try { if (splitContainer1 != null) { // Use the value of the inner content of the Dexterity-based // window, saved from the GetPreferredClientSize method. splitContainer1.SplitterDistance = AboutBoxSize.Width; splitContainer1.IsSplitterFixed = true; } } catch (ArgumentOutOfRangeException) { // Invalid size specified -- Ignore the error } }
You must specify which control on your form will host the Dexterity-based window content. You do this by overriding the protected DexHostContainer method. The method must return the control to be used so the Dexterity runtime can display the content.
The following example is the C# code that specifies the left panel of the SplitContainer control will be used to host the Dexterity-based window content. The code is part of the class for the new form, located in the same class as the default constructor. It overrides the protected DexHostContainer method.
protected override Control DexHostContainer { get { return splitContainer1.Panel1; } }
You can add additional controls to the new form simply by dragging them out from the Toolbox, just as you would any other .NET application.
If your code must interact with the Dexterity-based content (such as setting or retrieving window fields, or accessing the table buffers for the form) you can do this using techniques from Visual Studio Tools. You will need to include references to the Microsoft.Dexterity.Bridge assembly, as well as the application assembly for each dictionary whose resources you want to access. Often, this will be the application assembly for the Dynamics dictionary. You can register for Visual Studio Tools events in the form factory class. Refer to the Visual Studio Tools Programmer’s Guide for more information.
The following C# code is the complete form code for the new form used to add additional controls to the About Box window in Microsoft Dynamics GP.
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using Microsoft.Dexterity.Shell; namespace FormFactorySample { public partial class SampleForm : DexTaskForm { static Size AboutBoxSize; public SampleForm() { InitializeComponent(); } public SampleForm(string name, DexWindowType windowType, FormFlags flags, WindowState windowState, System.Drawing.Size minClientSize, System.Drawing.Size clientSize, bool hResizeable, bool vResizeable, short productId, short formId, short windowId, bool modified) { InitializeComponent(); } protected override Size GetPreferredClientSize(Size dexClientSize, DexWindowType windowType, short productId, short formId, short windowId, bool modified, bool apply) { Size baseClassSize; if (apply) { // Store the size of the About Box content area AboutBoxSize = dexClientSize; // Query the base class to get the outer dimensions of the Dexterity // window baseClassSize = base.GetPreferredClientSize(dexClientSize, windowType, productId, formId, windowId, modified, apply); // Add width for the splitter and new control area baseClassSize.Width += (splitContainer1.SplitterWidth + 150); return baseClassSize; } else { return base.GetPreferredClientSize(dexClientSize, windowType, productId, formId, windowId, modified, apply); } } protected override void OnResize(EventArgs e) { // Call OnResize for the base class base.OnResize(e); // When the window is resized, set the position of the splitter try { if (splitContainer1 != null) { // Use the value of the inner content of the Dexterity-based // window, saved from the GetPreferredClientSize method. splitContainer1.SplitterDistance = AboutBoxSize.Width; splitContainer1.IsSplitterFixed = true; } } catch (ArgumentOutOfRangeException) { // Invalid size specified -- Ignore the error } } protected override Control DexHostContainer { get { return splitContainer1.Panel1; } } private void button1_Click(object sender, EventArgs e) { MessageBox.Show("This is .NET code"); } } }