Ranorex 2.0 and Controls

Ask general questions here.
Captain Nemo
Posts: 17
Joined: Tue Dec 02, 2008 10:09 am

Ranorex 2.0 and Controls

Post by Captain Nemo » Tue Jan 06, 2009 12:21 pm

Anyone know how to get the underlying Control from an Element?

User avatar
Support Team
Site Admin
Site Admin
Posts: 11709
Joined: Fri Jul 07, 2006 4:30 pm
Location: Graz, Austria

Post by Support Team » Wed Jan 07, 2009 11:37 am

There are fundamental differences between the ways Ranorex 1.5 and Ranorex 2.0 represent GUI elements:
In Ranorex 1.5 every window (i.e. every GUI element having a window handle) is represented as a Control object. GUI elements inside a window, not having window handles by themselves are represented by Element objects.
Ranorex 2.0 represents all GUI elements by Element objects. Each element has a distinct role and can have multiple capabilities. The role depends on the type of the GUI element, capabilities provide additional features specific to the technology Ranorex uses to interact with the GUI element. E.g. both a Win32 button and a WinForms button have the Button role. The Win32 button has the NativeWindow capability (giving access to its window handle), whereas the WinForms button has the Control capability providing additional features for Windows Forms controls. To use capability features you can create adapters from elements:

Code: Select all

Element buttonElement = "pathToButton";
Control buttonControl = new Control(buttonElement);
// or simply
Control buttonControl = "pathToButton";
Creating an adapter from an element will only work if the element provides the corresponding capability, otherwise a CapabilityNotSupportedException will be raised.

So, there is no "underlying" control of an element, however, you can create a Control adapter from an element if it supports the Control capability. Just be sure to have references to the Ranorex plugin DLLs in your project when using plugin specific adapters.

Regards,
Alex
Ranorex Support Team

Captain Nemo
Posts: 17
Joined: Tue Dec 02, 2008 10:09 am

Post by Captain Nemo » Wed Jan 07, 2009 2:31 pm

That works as to getting the control. It even tells me what it is from the Control Type Property. But I want to be able to get hold of what it actually is.

The reason I want to do this, is because the GUI I'm trying to automate gives me a whole bunch of Ranorex.Unknown entries in my repository because the controls are custom, and don't report their roles. I can imagine this being the case for lots of GUI's out there that don't use standard WinForms controls for everything.

The Control instance gained from the above code tells me what the object is, my thinking would be to get at that object and interrogate it's properties myself.

User avatar
Support Team
Site Admin
Site Admin
Posts: 11709
Joined: Fri Jul 07, 2006 4:30 pm
Location: Graz, Austria

Post by Support Team » Thu Jan 08, 2009 9:42 am

As the actual Windows.Forms.Control you want to get access to resides in another process, you can't get a direct reference to that object. However, the Control adapter provides methods to get/set properties of the control (GetPropertyValue and SetPropertyValue) and to invoke methods on the control (InvokeMethod).

Code: Select all

Control myCustomControl = "pathToCustomControl";
object customPropertyValue = myCustomControl.GetPropertyValue("MyCustomPropertyName");
The only thing to be aware of is that you implicitly access a control in another process and that all parameters and return values of the properties/methods need to be serializable (e.g. all primitive types are serializable). If the values are not serializable, you can use the Control.InvokeRemotely method as a workaround.

I wrote a blog covering this topic some time ago. It was written for Ranorex 1.5, but everything written there is true for Ranorex 2.0 as well:
http://www.ranorex.com/blog/transfering ... et-control

Regards,
Alex
Ranorex Support Team

Captain Nemo
Posts: 17
Joined: Tue Dec 02, 2008 10:09 am

Post by Captain Nemo » Thu Jan 08, 2009 12:01 pm

Works a treat, thanks.

Captain Nemo
Posts: 17
Joined: Tue Dec 02, 2008 10:09 am

Post by Captain Nemo » Mon Jan 12, 2009 11:04 am

Now I've hit the serialization and transferring to .Net Control issues.

The Blog makes some sense, however, the 2.0 implementation of Ranorex.Plugin.RemotelyInvokedDelegate expects a Ranorex Control rather than the Windows control in the demo code.

Any code showing how this works?

User avatar
Support Team
Site Admin
Site Admin
Posts: 11709
Joined: Fri Jul 07, 2006 4:30 pm
Location: Graz, Austria

Post by Support Team » Tue Jan 13, 2009 11:13 am

Imagine you have a class MyUserControl inheriting from System.Windows.Forms.Control, then you can construct a delegate that is executed in the process that is running that control. For the following sample you have to add a reference to the DLL that defines the MyUserControl class:

Code: Select all

static void Main()
{
    Ranorex.Control userControl = "pathToTheUserControl";
    string value = (string)userControl.InvokeRemotely(MethodToExecuteRemotely);
}

static object MethodToExecuteRemotely(System.Windows.Forms.Control control, object inputData)
{
    // this code is executed in the automated process
    MyUserControl myControl = control as MyUserControl;
    if (myControl != null)
    {
        string stringValue = myControl.SomeProperty.Name;
        return stringValue;
    }
    return null;
}
Just be sure that the method is declared static and that all parameters as well as return values are serializable.

Regards,
Alex
Ranorex Support Team

rcd.guerra
Posts: 29
Joined: Tue Mar 03, 2009 11:43 pm

Post by rcd.guerra » Tue Apr 14, 2009 12:19 pm

Hi there guys,

i'm not getting it all here...

you say that the InvokeRemotely() method is to help in getting unserializable data from the process running the control.

In the end you say "Just be sure that the method is declared static and that all parameters as well as return values are serializable. "

This is a way to get unserializable data...

Please clarify me as we are having an issue with the ChartFx.AxisX property which is not serializable. We are using the procedure above to get the value as follows:

Code: Select all

Ranorex.Control chart = "pathToChart";
try
{
    string axisXtitle = (string) chart.InvokeRemotely(GetAxisXTitle);					
} 
catch (Exception ex)
{
    throw ex;
}

private static string GetAxisXTitle(System.Windows.Forms.Control control, object inputData)
{
    ChartFX.WinForms.Chart chart = control as ChartFX.WinForms.Chart;
    
    if(chart.AxisX != null)
    {  
         return chart.AxisX.Title.ToString();
    }
    
    return string.Empty;
}
Test execution throws an ActionFailedException stating "Action 'invokeremotely' failed on element '{Unknown:mChart}'. ---> System.NullReferenceException: Object"."

Should i be passing a "System.Windows.Forms.Control" to GetAxisXTitle() or a "ChartFx.WinForms.Chart" ?

Thanks in advance!

Cheers,
Ricardo

User avatar
Support Team
Site Admin
Site Admin
Posts: 11709
Joined: Fri Jul 07, 2006 4:30 pm
Location: Graz, Austria

Post by Support Team » Tue Apr 14, 2009 1:15 pm

rcd.guearra wrote:you say that the InvokeRemotely() method is to help in getting unserializable data from the process running the control.
In the end you say "Just be sure that the method is declared static and that all parameters as well as return values are serializable. "
You can't get unserializable data directly, even with the InvokeRemotely method. However, using the InvokeRemotely method you can split up the unserializable data into chunks of serializable bits and return them to the automating process.

I assume that in your GetAxisXTitle method the chart variable is null (did you pass the element corresponding to the right control?) and that's why a NullReferenceException is raised. Please make sure that the ControlType attribute of the chart variable (the one you assign the "pathToChart" path to) is "ChartFX.WinForms.Chart".

Regards,
Alex
Ranorex Support Team

rcd.guerra
Posts: 29
Joined: Tue Mar 03, 2009 11:43 pm

Post by rcd.guerra » Tue Apr 14, 2009 4:15 pm

I assume that in your GetAxisXTitle method the chart variable is null (did you pass the element corresponding to the right control?) and that's why a NullReferenceException is raised.
Well, it seems this exception is thrown inside the delegate. How can i debug the code inside the delegate method as it is being run in another process ? I tried attaching my application process and it crashes Ranorex...
Please make sure that the ControlType attribute of the chart variable (the one you assign the "pathToChart" path to) is "ChartFX.WinForms.Chart".
The ControlType is correct.

I've also double-checked that the chart element is not null and it is the correct one, at the time the InvokeRemotely() method is being called.

Should i be passing a System.Windows.Forms.Control to the GetAxisXTitle() method or a Ranorex.Control ?

Thanks,
Ricardo

User avatar
Support Team
Site Admin
Site Admin
Posts: 11709
Joined: Fri Jul 07, 2006 4:30 pm
Location: Graz, Austria

Post by Support Team » Tue Apr 14, 2009 5:13 pm

rcd.guerra wrote:Should i be passing a System.Windows.Forms.Control to the GetAxisXTitle() method or a Ranorex.Control ?
What do you mean by that? You should not be passing anything to the GetAxisXTitle method, you simply call chart.InvokeRemotely(GetAxisXTitle); where chart is a Ranorex.Control.

You should be able to attach to the processing being automated using RanorexStudio or VisualStudio. What do you mean with "it crashes Ranorex"? Does RanorexStudio crash when you attach to your application?

Regards,
Alex
Ranorex Support Team

rcd.guerra
Posts: 29
Joined: Tue Mar 03, 2009 11:43 pm

Post by rcd.guerra » Tue Apr 14, 2009 6:58 pm

Alex,
You should not be passing anything to the GetAxisXTitle method, you simply call chart.InvokeRemotely(GetAxisXTitle); where chart is a Ranorex.Control.
What i wanted to ask was if the GetAxisXTitle() signature was correct.
The first parameter is "System.Windows.Forms.Control control". Is this correct or should it be a "Ranorex.Control" ?
You should be able to attach to the processing being automated using RanorexStudio or VisualStudio. What do you mean with "it crashes Ranorex"? Does RanorexStudio crash when you attach to your application?
In RanorexStudio, once i attach the process being automated an exception is thrown stating "JIT settings most likely bad configured".

Thanks,
Ricardo

User avatar
Support Team
Site Admin
Site Admin
Posts: 11709
Joined: Fri Jul 07, 2006 4:30 pm
Location: Graz, Austria

Post by Support Team » Wed Apr 15, 2009 1:21 pm

Hello rcd.querra,
I have tried your code above with the BubbleChart ChartFX7 Sample Application and it worked perfectly.
Maybe you use a wrong RxPath. The type in Ranorex Spy should be from ControlType "ChartFX.WinForms.Chart"

The signature of the GetAxisXTitle method is correct. The first parameter needs to be of type System.Windows.Forms.Control - if you had another type there, your code would not compile.

Regards,
Christian
Ranorex Support Team

rcd.guerra
Posts: 29
Joined: Tue Mar 03, 2009 11:43 pm

Post by rcd.guerra » Wed Apr 15, 2009 5:05 pm

Its very strange, we tried in a clean solution and it works correctly. Thanks!

When we spy the element, its ControlType is the correct (ChartFX.WinForms.Chart) but in the Repository the element is a Ranorex.Unknown.

For calling the InvokeMethod() we need a Ranorex.Control. How can we convert a Ranorex.Unknown in a Ranorex.Control ?

By now we are getting a Ranorex.Control directly in the code through its RanoreXPath, which i think its not clean since we hold a repository.

Thanks in advance.

Feature request: show a repository item type in the Properties window or enable direct navigation to the source code.

User avatar
Support Team
Site Admin
Site Admin
Posts: 11709
Joined: Fri Jul 07, 2006 4:30 pm
Location: Graz, Austria

Post by Support Team » Fri Apr 17, 2009 9:09 am

.NET User Controls will almost always have the role Ranorex.Unknown, unless it's derived from a standard Windows Forms control. However, every Windows Forms Control (including user controls) have the Control capability, so you can use the Ranorex.Control adapter on those elements.
There are several ways to get a Ranorex.Control adapter from another adapter like Unknown:

Code: Select all

Unknown button = repo.MyApp.MyButton;
Control buttonControl = button.As<Control>();
// or
buttonControl = new Control(button);
Currently, in the repository editor you see which adapter is created for the repository item by the icon next to it. I add a feature request that the adapter type should be shown in the property grid of the item.

Regards,
Alex
Ranorex Support Team