Spinner and DateTimePicker in Version 0.16

Jul 2, 2008 at 1:46 PM
I downloaded version 0.16, and am experiencing the following problems

1. For the spinner control I am getting the following exception

Bricks.BricksException: Error invoking Spinner.set_Value ---> Core.WhiteAssertionException: Could not find Raw Spinner Element containing the value
   at Core.UIItems.Spinner.GetValuePattern() in C:\Program Files\White3\Core\UIItems\Spinner.cs:line 34
   at Core.UIItems.Spinner.set_Value(Int32 value) in C:\Program Files\White3\Core\UIItems\Spinner.cs:line 27

It seems to be able to get a handle on the spinner control, but not the inner elements.

2. For the datetimepicker control I am having a problem with setting the value into the control when it contains a checkbox, therefore the control consists of CheckBox, Month, Day, Year. The function in the DateTimePicker.cs class
        public virtual void SetDate(DateTime dateTime, DateFormat dateFormat)
        {
            keyboard.Send(dateFormat.DisplayValue(dateTime, 0).ToString(), actionListener);
            keyboard.PressSpecialKey(KeyboardInput.SpecialKeys.RIGHT, actionListener);
            keyboard.Send(dateFormat.DisplayValue(dateTime, 1).ToString(), actionListener);
            keyboard.PressSpecialKey(KeyboardInput.SpecialKeys.RIGHT, actionListener);
            keyboard.Send(dateFormat.DisplayValue(dateTime, 2).ToString(), actionListener);
        }
attempts to write the first part of the date into the checkbox, move right, then write the second part of the date into the field, move right, then write the third part of the date into the field This obviously leads to the incorrect date being set. Additionally there is no mechanism to select/unselect the checkbox.

I temporarily got around the issue by first setting focus to the field, sending a space to the control (which selects the checkbox), and then altered the above function
        public virtual void SetDate(DateTime dateTime, DateFormat dateFormat)
        {
            keyboard.PressSpecialKey(KeyboardInput.SpecialKeys.RIGHT, actionListener);
            keyboard.Send(dateFormat.DisplayValue(dateTime, 0).ToString(), actionListener);
            keyboard.PressSpecialKey(KeyboardInput.SpecialKeys.RIGHT, actionListener);
            keyboard.Send(dateFormat.DisplayValue(dateTime, 1).ToString(), actionListener);
            keyboard.PressSpecialKey(KeyboardInput.SpecialKeys.RIGHT, actionListener);
            keyboard.Send(dateFormat.DisplayValue(dateTime, 2).ToString(), actionListener);
        }
which moves right from the checkbox to the first field.
Coordinator
Jul 2, 2008 at 7:24 PM
1. I am assuming it is a winform app. Would it possible for you to create a sample helloworld kind of app with a spinner control it, against which I can try. If you do have the source you can see there is test for Spinner. May be your spinned is shown differently by UIAutomation. I would want to know what it is so that I can fix it.
2. I will figure how to get a checkbox and try to fix this issue.
Thanks for pointing out the issues.
Oct 10, 2008 at 5:05 AM
Edited Oct 10, 2008 at 5:06 AM
gmcgibbon64,

Did you manage to find the source of the error with the spinner control? I got something similar when accessing Spinner.Value and I assume there is something missing in the UI Automation Implementation of the Spinner in question. The error is thrown from UIItems.Spinner's get_Value() method.

Vivek, do you have any ideas on what could be missing so that GetValuePatern() cannot locate the spinner element? The White code throwing the error follows:

private ValuePattern GetValuePattern()
{
AutomationElement spinnerElementContainingValue = this.finder.FindChildRaw(AutomationSearchCondition.ByAutomationId(base.automationElement.Current.AutomationId).OfControlType(ControlType.Spinner));
if (spinnerElementContainingValue == null)
{
throw new WhiteAssertionException("Could not find Raw Spinner Element containing the value");
}
return (ValuePattern) spinnerElementContainingValue.GetCurrentPattern(ValuePattern.Pattern);
}

BTW, I'm running the latest White 0.17.

Thanks,
-Konstantin
Coordinator
Oct 13, 2008 at 5:53 AM
Can you download the source code and try running SpinnerTest and let me know if is passes?
Oct 13, 2008 at 6:10 AM
Thanks for your reply, Vivek.

Looks like many people hit difficulties downloading the source, but I'll give it a go hopefully later today. I guess I'll quickly find some useful info googling how to download CodePlex project source.

BTW, can you post just the SpinnerTest attached to this thread? It should help others getting the same problem in future.

Thanks,
-Konstantin
Oct 13, 2008 at 11:59 AM
Edited Oct 13, 2008 at 12:05 PM
Sorry, I'm unable to download the source. I'm running the latest TortoiseSVN (1.5.4) and according to the post by Sara Ford here

http://blogs.msdn.com/codeplex/archive/2008/09/14/codeplex-launches-support-for-tortoisesvn.aspx

I should be able to just load the latest files by loading the following URL into repo-browser:
https://white.svn.codeplex.com/svn

There is no error on connecting but I get no files in the browser. Calling Tortoise's "checkout" in Windows Explorer makes no difference.

Just as an example, if I enter the SvnBridge project, I see the source. The URL is:
https://svnbridge.svn.codeplex.com/svn

Can you help with this one?

Thanks,
Konstantin


Oct 15, 2008 at 12:40 PM
Edited Oct 15, 2008 at 12:42 PM
Hello, Vivek.

I've looked once again in the code of White regarding this issue. It looks like the above posted code from GetValuePattern() method actually searches for a Spinner UI Element as a child of the main Spinner.
Does that mean there is a UI Automation Spinner type requirement that the custom control of type Spinner should have a child of type Spinner as well? The actual child of our custom Spinner (NumericUpDown) is an editable TextBox (ControlType.Edit). If there is such a requirement, do you have references to share?

I've searched for a NumericUpDown for WPF custom control implementation and found this one (see the last post):

http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/9bf30f5f-2425-4f9e-96d6-8a88c36d8860/

The editable TextBox of course has again ControlType.Edit type. So it throws the exact same error accessing the Spinner.Value property with White.

Your assistance is greatly appreciated, thanks.
-Konstantin
Coordinator
Oct 16, 2008 at 8:28 AM
Sorry for the confusion about the source code. What I meant was you can download the source zip? This is published along with the binary release.
Oct 16, 2008 at 10:37 AM
I see. Yes, it looks like the test passes. Is the below the expected output?

-----------------------------------------------------------------------

------ Test started: Assembly: Core.dll ------

[2008-10-16 13:25:46,221][INFO ] Using BusyTimeout=10000 for White/Core
[2008-10-16 13:25:46,257][INFO ] Using WaitBasedOnHourGlass=True for White/Core
[2008-10-16 13:25:46,257][INFO ] Using LogActions=False for White/Core
[2008-10-16 13:25:46,257][INFO ] Using WorkSessionLocation=. for White/Core
[2008-10-16 13:25:46,257][INFO ] Using UIAutomationZeroWindowBugTimeout=5000 for White/Core
[2008-10-16 13:25:46,257][INFO ] Using PopupTimeout=5000 for White/Core
[2008-10-16 13:25:46,257][INFO ] Using TooltipWaitTime=3000 for White/Core
[2008-10-16 13:25:46,257][INFO ] Using SuggestionListTimeout=3000 for White/Core
[2008-10-16 13:25:46,257][INFO ] Using DefaultDateFormat=Month,Day,Year for White/Core
[2008-10-16 13:25:46,257][INFO ] Using DragStepCount=1 for White/Core
[2008-10-16 13:25:46,258][INFO ] Using InProc=False for White/Core
Section: Bricks in SectionGroup: Bricks is not configured in Configuration file
Using RecheckDurationInMilliseconds=100 for Bricks/Bricks

3 passed, 0 failed, 0 skipped, took 16.23 seconds.

-----------------------------------------------------------------------

What do you think about the child with Spinner ControlType expected from the Spinner class?  Would White support NumericUpDown controls having an editable input as a child?

-Konstantin
Coordinator
Oct 18, 2008 at 5:42 PM
Please use UIItem.GetElement method to get hold of AutomationElement within any UIItem. In this case inside Spinner. This is a fallback option when white doesn't support certain UIItems.
Please can you send me the output of spinner.LogStructure() so that I can accomodate this in future releases.
Oct 20, 2008 at 7:38 AM
Thanks and sure, I'd be happy to give you more details on the structure so you can improve White's support of UI Elements.

Unfortunately calling LogStructure() on the NumericUpDown Spinner causes System.StackOverflowException to be thrown. The CallStack looks like this:

----------------------------------------

    [External Code]   
>    Core.dll!Core.UIItems.UIItem.Bounds.get() Line 77 + 0x27 bytes    C#
     Core.dll!Core.UIItems.WindowItems.Window.ActionPerforming(Core.UIItems.UIItem uiItem = {Core.UIItems.Spinner}) Line 403 + 0xb bytes    C#
     Core.dll!Core.Interceptors.ScrollInterceptor.PreProcess(Castle.Core.Interceptor.IInvocation invocation = {SpinnerProxye50da9ec83cc46ea9b5c70f094c5d105.InvocationToString_17}, object target = {Core.Interceptors.CoreInterceptContext}) Line 13 + 0x49 bytes    C#
     Bricks.dll!Bricks.DynamicProxy.DynamicProxyInterceptors.Process.AnonymousMethod(Bricks.DynamicProxy.DynamicProxyInterceptor obj = {Core.Interceptors.ScrollInterceptor}) Line 19 + 0x1c bytes    C#
     [External Code]   
     Bricks.dll!Bricks.DynamicProxy.DynamicProxyInterceptors.Process(Castle.Core.Interceptor.IInvocation invocation = {SpinnerProxye50da9ec83cc46ea9b5c70f094c5d105.InvocationToString_17}, Bricks.DynamicProxy.InterceptContext interceptedContext = {Core.Interceptors.CoreInterceptContext}) Line 19 + 0x29 bytes    C#
     Core.dll!Core.Interceptors.CoreInterceptor.Intercept(Castle.Core.Interceptor.IInvocation invocation = {SpinnerProxye50da9ec83cc46ea9b5c70f094c5d105.InvocationToString_17}) Line 24 + 0x28 bytes    C#
     Castle.DynamicProxy2.dll!Castle.DynamicProxy.AbstractInvocation.Proceed() Line 165 + 0x23 bytes    C#
     [External Code]   
     Core.dll!Core.Interceptors.LogInterceptor.Log(Castle.Core.Interceptor.IInvocation invocation = {SpinnerProxye50da9ec83cc46ea9b5c70f094c5d105.InvocationToString_17}, string prefix = "Starting: ") Line 24 + 0x7f bytes    C#
     Core.dll!Core.Interceptors.LogInterceptor.PreProcess(Castle.Core.Interceptor.IInvocation invocation = {SpinnerProxye50da9ec83cc46ea9b5c70f094c5d105.InvocationToString_17}, object target = {Core.Interceptors.CoreInterceptContext}) Line 13 + 0xe bytes    C#
     Bricks.dll!Bricks.DynamicProxy.DynamicProxyInterceptors.Process.AnonymousMethod(Bricks.DynamicProxy.DynamicProxyInterceptor obj = {Core.Interceptors.LogInterceptor}) Line 19 + 0x1c bytes    C#
     [External Code]   
     Bricks.dll!Bricks.DynamicProxy.DynamicProxyInterceptors.Process(Castle.Core.Interceptor.IInvocation invocation = {SpinnerProxye50da9ec83cc46ea9b5c70f094c5d105.InvocationToString_17}, Bricks.DynamicProxy.InterceptContext interceptedContext = {Core.Interceptors.CoreInterceptContext}) Line 19 + 0x29 bytes    C#
     Core.dll!Core.Interceptors.CoreInterceptor.Intercept(Castle.Core.Interceptor.IInvocation invocation = {SpinnerProxye50da9ec83cc46ea9b5c70f094c5d105.InvocationToString_17}) Line 24 + 0x28 bytes    C#
     Castle.DynamicProxy2.dll!Castle.DynamicProxy.AbstractInvocation.Proceed() Line 165 + 0x23 bytes    C#
     [External Code]   
     Core.dll!Core.Interceptors.LogInterceptor.Log(Castle.Core.Interceptor.IInvocation invocation = {SpinnerProxye50da9ec83cc46ea9b5c70f094c5d105.InvocationToString_17}, string prefix = "Starting: ") Line 24 + 0x7f bytes    C#
     Core.dll!Core.Interceptors.LogInterceptor.PreProcess(Castle.Core.Interceptor.IInvocation invocation = {SpinnerProxye50da9ec83cc46ea9b5c70f094c5d105.InvocationToString_17}, object target = {Core.Interceptors.CoreInterceptContext}) Line 13 + 0xe bytes    C#
     Bricks.dll!Bricks.DynamicProxy.DynamicProxyInterceptors.Process.AnonymousMethod(Bricks.DynamicProxy.DynamicProxyInterceptor obj = {Core.Interceptors.LogInterceptor}) Line 19 + 0x1c bytes    C#

----------------------------------------

The error is thrown by UIItem.cs, the rectangle boundaries getter.

Would it be convenient for you to send me an email (I assume you have access to my account's email, don't you?) and I can reply you with a sample WPF project along with assembly reference of the NumericUpDown control in question. I guess it will help you to investigate the structure and apply the necessary change in the code.

Looking forward to hearing from you,
-Konstantin


Coordinator
Oct 26, 2008 at 7:01 PM
You are facing the problem because of LogActions = true. I discovered that this is bug in this. I have removed this feature altogether for next release, as this is not very useful.
Please remove this or make this false. This property has nothing to do with LogStructure().
Oct 27, 2008 at 6:45 AM
Good, another one bytes the dust. Sounds like I'm able to help at least a bit...

I've set it to "false" and the LogStructure() passes now. Unfortunately I don't get the log file. I tried both with log4net.config and log4net section in app.config. I've used the sample from your page. BTW, you might want to extend the log4net explanation in Home -> Configuration page.

So how can I make sure the log4net is properly configured? log4net.config is not being copied into bin/debug output folder. I don't get any errors on running the test (which actually calls LogStructure() only). The output does not mention log4net except that the .dll is being copied.

Can I get some useful info (for you) from UI Spy or Visual UIA Verify? Let me know what else would you need.

-Konstantin
Oct 27, 2008 at 7:00 AM
Vivek, here is the structure I got in UI Spy. I've put the control types as tree nodes:

- Spinner
  - Edit
    - ScrollBar
    - ScrollBar
  - Button
  - Button

So our Spinner has editable text box as well as two repeat buttons children. The text box children are scroll bars.

BTW, the available UIA Verify Spinner tests of this NumericUpDown control pass (if that matters).

Hope this helps.

-Konstantin
Coordinator
Oct 27, 2008 at 7:04 AM
Yes you are indeed helping. I dont know about UIAVerify but UISpy is not very reliable.

I have updated the documentation with this.
In order copy over log4net.config to output directory you would need to set open properties on file in VisualStudio and set "Copy To Output Directory" = "Copy if newer" or "Copy always"
Oct 27, 2008 at 7:38 AM
Got it.

That doesn't create the While.log file though. I've performed a search for the whole application. The log file should be created in the root folder, correct?
Coordinator
Oct 28, 2008 at 12:03 PM
Can you send me the zip of your test project?
Oct 28, 2008 at 12:25 PM
Sure. Is there a private way I can send it to you? I'm unable to find your email.

This version is still unofficial. I can submit an issue sending the latest official .dll version, but UI Automation is not implemented there within the NumericUpDown control. Or, I can submit the project in your Issue Tracker somewhere next week.

Let me know what you think. When is the next White version 0.18 expected?

Thanks,
-Konstantin
Coordinator
Oct 29, 2008 at 2:10 AM
You can contact me via the codeplex userid. Click on the name link and can follow the obvious steps.
Oct 29, 2008 at 5:42 AM
OK, I've sent you a message.
Nov 26, 2008 at 4:30 PM
Can I ask if there is any more work done with the NullCheckBox.

Reason I ask is I tried to create my own NullDateTimePicker using the example you gave in
the wiki but every time I tried to access the Container it said it found no items inside of it. This then
threw could not invoke errors.

Is there anything I need to do to populate the container?
Coordinator
Dec 5, 2008 at 2:51 PM
can you post the source of of the custom ui item you are using?
Dec 11, 2008 at 8:39 AM
Ok Below is the code for my Nullable DataTime picker.

[ControlTypeMapping(CustomUIItemType.Pane)]
    public class NullDateTimePicker : CustomUIItem
    {
        public NullDateTimePicker(AutomationElement automationElement, ActionListener actionListener)
            : base(automationElement, actionListener)
        {
        }

        //Empty constructor is mandatory with protected or public access modifier.
        protected  NullDateTimePicker()
        {
        }
        
        public virtual DateTime Date
        {
            get { return DateTime.Parse((string)Property(ValuePattern.ValueProperty)); }
            set { SetDate(value,DateFormat.DayMonthYear); }
        }

        private CheckBox CheckBox
        {
            get
            {
                return Container.Get<CheckBox>(SearchCriteria.ByControlType(typeof (CheckBox)));
            }
        }

        private DateTimePicker DateTimePicker
        {
            get
            {
                return Container.Get<DateTimePicker>(SearchCriteria.ByControlType(typeof (DateTimePicker)));
            }
        }

        private void SetDate(DateTime dateTime, DateFormat dateFormat)
        {
            CheckBox.Select();
            DateTimePicker.SetDate(dateTime,dateFormat);
        }
    }

If you put a debug line on either the get of the checkbox or the datetime picker, it dosn't seem to have any items
Coordinator
Dec 14, 2008 at 8:04 AM
Do you know if UIAutomation shows any values inside the Pane? You can try UISpy to check this.
Also you can do Debug.LogStructure for the customuiitem to see what is in there.