Dynamically Invoking Windows Forms Methods

Dynamic invoke enables you to directly call methods, retrieve properties, or set properties, on an actual instance of a control in the application under test. You can also call methods and properties that are not available in the Silk4NET API for this control. Dynamic invoke is especially useful when you are working with custom controls, where the required functionality for interacting with the control is not exposed through the Silk4NET API.

Call dynamic methods on objects with the Invoke method. To retrieve a list of supported dynamic methods for a control, use the GetDynamicMethodList method.

Call multiple dynamic methods on objects with the InvokeMethods method. To retrieve a list of supported dynamic methods for a control, use the GetDynamicMethodList method.

Retrieve dynamic properties with the GetProperty method and set dynamic properties with the SetProperty method. To retrieve a list of supported dynamic properties for a control, use the GetPropertyList method.

For example, to call a method named SetTitle, which requires the title to be set as an input parameter of type string, on an actual instance of a control in the application under test, type the following:
control.Invoke("SetTitle", "my new title")
Note: Typically, most properties are read-only and cannot be set.
Note: Reflection is used in most technology domains to call methods and retrieve properties.

The Invoke Method

For a Windows Forms or a WPF control, you can use the Invoke method to call the following methods:
  • Public methods that the MSDN defines for the control.
  • Public static methods that the MSDN defines.
  • User-defined public static methods of any type.

First Example for the Invoke Method

For an object of the Silk4NET type DataGrid, you can call all methods that MSDN defines for the type System.Windows.Forms.DataGrid.

To call the method IsExpanded of the System.Windows.Forms.DataGrid class, use the following code:
//VB .NET code
Dim isExpanded As Boolean = dataGrid.Invoke("IsExpanded", 3)
//C# code
bool isExpanded = (bool) dataGrid.Invoke("IsExpanded", 3);

Second Example for the Invoke Method

To invoke the static method String.Compare(String s1, String s2) inside the AUT, use the following code:
//VB .NET code
Dim result as Integer = (Integer) mainWindow.Invoke("System.String.Compare", "a", "b")
//C# code
int result = (int) mainWindow.Invoke("System.String.Compare", "a", "b");

Third Example for the Invoke Method

This example shows how you can dynamically invoke the user-generated method GetContents.

You can write code which you can use to interact with a control in the application under test (AUT), in this example an UltraGrid. Instead of creating complex dynamic invoke calls to retrieve the contents of the UltraGrid, you can generate a new method GetContents and then just dynamically invoke the new method.

In Visual Studio, the following code in the AUT defines the GetContents method as a method of the UltraGridUtil class:
//C# code, because this is code in the AUT 
namespace UltraGridExtensions {
  public class UltraGridUtil {
    /// <summary>
    /// Retrieves the contents of an UltraGrid as nested list
    /// </summary>
    /// <param name="grid"></param>
    /// <returns></returns>
    public static List<List<string>> GetContents(Infragistics.Win.UltraWinGrid.UltraGrid grid) {
      var result = new List<List<string>>();
      foreach (var row in grid.Rows) {
        var rowContent = new List<string>();
        foreach (var cell in row.Cells) {
          rowContent.Add(cell.Text);
        }
        result.Add(rowContent);
      }
      return result;
    }
  }
}
The code for the UltraGridUtil class needs to be added to the AUT. You can do this in the following ways:
  • The application developer can compile the code for the class into the AUT. The assembly needs to be already loaded.
  • You can create a new assembly that is loaded into the AUT during test execution.
To load the assembly, you can use the following code:
FormsWindow.LoadAssembly(String assemblyFileName)
You can load the assembly by using the full path, for example:
mainWindow.LoadAssembly("C:/temp/ultraGridExtensions.dll")
You can also find the location of the assembly by using the Location method:
//VB.NET code
Dim assemblyLocation = GetType(UltraGridExtensions.UltraGridUtil).Assembly.Location
mainWindow.LoadAssembly(assemblyLocation)
//C# code
string assemblyLocation = typeof(UltraGridExtensions.UltraGridUtil).Assembly.Location;
mainWindow.LoadAssembly(assemblyLocation);
When the code for the UltraGridUtil class is in the AUT, you can add the following code to your test script to invoke the GetContents method:
var contents = (IList) mainWindow.Invoke("UltraGridExtensions.UltraGridUtil.GetContents", ultraGrid);

The mainWindow object, on which the Invoke method is called, only identifies the AUT and can be replaced by any other object in the AUT.

The InvokeMethods Method

For a Windows Forms or a WPF control, you can use the InvokeMethods method to invoke a sequence of nested methods. You can call the following methods:
  • Public methods that the MSDN defines for the control.
  • Public static methods that the MSDN defines.
  • User-defined public static methods of any type.

Example: Getting the Text Contents of a Cell in a Custom Data Grid

To get the text contents of a cell of a custom data grid from the Infragistics library, you can use the following C# code in the AUT:
string cellText = dataGrid.Rows[rowIndex].Cells[columnIndex].Text;
The following C# code sample gets the text contents of the third cell in the first row:
string cellText = dataGrid.Rows[0].Cells[2];
Scripting the same example by using the InvokeMethods method generates a relatively complex script, because you have to pass five methods with their corresponding parameters to the InvokeMethods method:
// C# code
var dataGrid = mainWindow.WPFControl("@automationId='Custom Data Grid'");
// Get text contents of third cell in first row.
var rowIndex = 0;
var columnIndex = 2;

var methodNames = new List<string>();
methodNames.Add("Rows"); 			 								// Get the list of rows from the grid.
methodNames.Add("get_Item"); 								// Get a specific row from the list of rows by using the indexer method.
methodNames.Add("Cells"); 											// Get the list of cells from the the row.
methodNames.Add("get_Item"); 								// Get a specific cell from the list of cells by using the indexer method.
methodNames.Add("Text"); 												// Get the text of the cell.
      
var parameters = new List<List<object>>();
parameters.Add(new List<object>());                  // Parameters for the Rows property.
parameters.Add(new List<object>() { rowIndex });     // Parameters for the get_Item method.
parameters.Add(new List<object>());                  // Parameters for the Cells property.
parameters.Add(new List<object>() { columnIndex });  // Parameters for the get_Item method.
parameters.Add(new List<object>());                  // Parameters for the Text property.

string cellText = (string)dataGrid.InvokeMethods(methodNames, parameters);
' VB .NET code
Dim dataGrid = mainWindow.WPFControl("@automationId='Custom Data Grid'")

' Get text contents of third cell in first row.
Dim rowIndex = 0
Dim column = 2

Dim methodNames = New List(Of String)()
methodNames.Add("Rows")                   ' Get the list of rows from the grid.
methodNames.Add("get_Item")               ' Get a specific row from the list of rows by using the indexer method.
methodNames.Add("Cells")                  ' Get the list of cells from the the row.
methodNames.Add("get_Item")               ' Get a specific cell from the list of cells by using the indexer method.
methodNames.Add("Text")                   ' Get the text of the cell.

Dim parameters = New List(Of List(Of Object))()
parameters.Add(New List(Of Object)())                  ' Parameters for the Rows property.
parameters.Add(New List(Of Object) From {rowIndex})    ' Parameters for the get_Item method.
parameters.Add(New List(Of Object)())                  ' Parameters for the Cells property.
parameters.Add(New List(Of Object) From {columnIndex}) ' Parameters for the get_Item method.
parameters.Add(New List(Of Object)())                  ' Parameters for the Text property.

Dim cellText As String = dataGrid.InvokeMethods(methodNames, parameters)
A better approach in such a case is to add code to the application under test and then to use the InvokeMethods method. For this example, add the GetCellText method to the AUT:
// C# code, if the AUT is implemented in C#.
public static string GetCellText(Infragistics.Win.UltraWinGrid.UltraGrid dataGrid, int rowIndex, int columnIndex) {
  return dataGrid.Rows[rowIndex].Cells[columnIndex].Text;
' VB code, if the AUT is implemented in VB.
public static string GetCellText(Infragistics.Win.UltraWinGrid.UltraGrid dataGrid, int rowIndex, int columnIndex) {
  return dataGrid.Rows[rowIndex].Cells[columnIndex].Text;
To get the text contents of the cell, dynamically invoke the GetCellText method from your test script:
// C# code
string cellText = (string) mainWindow.Invoke("GetCellText", dataGrid, rowIndex, columnIndex);
'VB .NET code
Dim cellText As String = mainWindow.Invoke("GetCellText", dataGrid, rowIndex, columnIndex)

For additional information, see Adding Code to the Application Under Test to Test Custom Controls.

Supported Methods and Properties

The following methods and properties can be called:
  • Methods and properties that Silk4NET supports for the control.
  • All public methods and properties that the MSDN defines for the control.
  • If the control is a custom control that is derived from a standard control, all methods and properties from the standard control can be called.

Supported Parameter Types

The following parameter types are supported:
  • All built-in Silk4NET types

    Silk4NET types includes primitive types (such as boolean, int, string), lists, and other types (such as Point and Rect).

  • Enum types

    Enum parameters must be passed as string. The string must match the name of an enum value. For example, if the method expects a parameter of the .NET enum type System.Windows.Visiblity you can use the string values of Visible, Hidden, or Collapsed.

  • .NET structs and objects

    .NET struct and object parameters must be passed as a list. The elements in the list must match one constructor for the .NET object in the test application. For example, if the method expects a parameter of the .NET type System.Windows.Vector, you can pass a list with two integers. This works because the System.Windows.Vector type has a constructor with two integer arguments.

  • Other controls

    Control parameters can be passed or returned as TestObject.

Returned Values

The following values are returned for properties and methods that have a return value:
  • The correct value for all built-in Silk4NET types. These types are listed in the Supported Parameter Types section.
  • All methods that have no return value return null in C# or Nothing in VB.