Udostępnij za pośrednictwem


Custom WPF Control’s custom properties

A number of customers have asked me about how to use the UI Test Extensibility model to get custom properties from a custom WPF control. e.g:-  I have a custom Button which does some animation when clicked. This button has 3 interesting properties – AnimationStartColor, AnimationEndColor & AnimationDuration. I need to add validations on these properties as part of my Coded UI Test.

 

Gautam has described this for a WinForms control in his blog - Extending supported properties set of a control. He describes how to get additional properties for a custom WinForms control. He has also blogged about a Utility function to get custom properties of a WPF control. I will be using these two blogs as the basis for building out my UI Test framework extension which will retrieve the  3 custom properties of my AnimatedButton.

 

NOTE: Record and Playback is working properly for my AnimatedButton. I am reusing the existing UI Test WPF plugin.

 

Animated Button

Here is the code for the WPF custom control AnimatedButton.

public AnimatedButton()
: base()
{
AnimationDuration = new Duration(TimeSpan.FromSeconds(3));
AnimationStartColor = Colors.Red;
AnimationEndColor = Colors.Blue;

Style s = new Style(typeof(Button));
String val = AnimationDuration.ToString() + ";" + AnimationStartColor.ToString() + ";" + AnimationEndColor.ToString(); s.Setters.Add(new Setter(AutomationProperties.ItemStatusProperty, val)); this.Style = s;
}

protected override void OnClick()
{
base.OnClick();
ColorAnimation buttonAnimation = new ColorAnimation(AnimationStartColor, AnimationEndColor, AnimationDuration);
Storyboard.SetTarget(buttonAnimation, (DependencyObject)this);
Storyboard.SetTargetProperty(buttonAnimation, new PropertyPath("Foreground.Color"));
Storyboard buttonAnimationStoryboard = new Storyboard();
buttonAnimationStoryboard.Children.Add(buttonAnimation);
buttonAnimationStoryboard.Begin(this);
}

 

Notice how I have stored the 3 custom properties in AutomationProperties.ItemStatus. I am using ItemStatus property to communicate the value of the custom properties from the Application to Visual Studio. Now let us look at how the UITest extension retrieves these values and uses them.

 

UI Test Extension Package

In order to build a UI Test extension, you need to create your Extension Package. See a very simple implementation of UI Test Extension Package below.

[assembly: Microsoft.VisualStudio.TestTools.UITest.Extension.UITestExtensionPackage(
"AnimatedButtonExtensionPackage",
typeof(AnimatedButton.AnimatedButtonExtensionPackage))]
namespace AnimatedButton
{
internal class AnimatedButtonExtensionPackage : UITestExtensionPackage
{

        public override object GetService(Type serviceType)
{
if (serviceType == typeof(UITestPropertyProvider))
{
if (propertyProvider == null) { propertyProvider = new PropertyProvider(); }
return propertyProvider;
} return null;
}

        public override void Dispose() {}
public override string PackageDescription {get { return "Animation Button Extension"; }}
public override string PackageName { get { return "Animation Button Extension"; } }
public override string PackageVendor { get { return "Mathew Aniyan"; }}
public override Version PackageVersion { get { return new Version(1, 0); } }
public override Version VSVersion { get { return new Version(10, 0); } }

        private UITestPropertyProvider propertyProvider;
}
}

 

Two key points to note in the above code.

1.  The assembly attribute used to identify a UI Test extension package.

2.  We are registering a property provider extension to be used.

 

Property Provider

Now for the implementation of the Property Provider which will retrieve the 3 custom properties that we have set in AutomationProperties.ItemStatus property of AnimatedButton and make it available in Coded UI Test.

I had to make changes in the GetPropertyValueInternal method in Gautam’s sample PropertyProvider. Here I split the ItemStatus property and return the interesting animation properties.

        private object GetPropertyValueInternal(UITestControl uiTestControl, string propertyName)
{
AutomationElement a = uiTestControl.NativeElement as AutomationElement;

            if (a.Current.ItemStatus == null || a.Current.ItemStatus.Length < 3)
return null;

            String[] animationProperties = a.Current.ItemStatus.Split(new char[] { ';' });
if (string.Equals(propertyName, AnimatedButton.PropertyNames.AnimationStartColor, StringComparison.OrdinalIgnoreCase))
{
return animationProperties[1];
}

            if (string.Equals(propertyName, AnimatedButton.PropertyNames.AnimationEndColor, StringComparison.OrdinalIgnoreCase))
{
return animationProperties[2];
}

            if (string.Equals(propertyName, AnimatedButton.PropertyNames.AnimationDuration, StringComparison.OrdinalIgnoreCase))
{
return animationProperties[0];
}

            throw new NotSupportedException();
}

 

Other customizations I had to make were -

a. Change the technology name to UIA in IsSupported() method. (Since we are doing this for WPF custom control)

b. Modify the extraPropertiesMap dictionary to have my new animation properties.

c. Modify GetSpecializedClass & GetPropertyNamesClassType  to return AnimatedButton.

My Animated Button specialized class looks like this:

public class AnimatedButton : WpfButton
{
public AnimatedButton(): this(null) { }
public AnimatedButton(UITestControl container): base(container) {
SearchProperties.Add(UITestControl.PropertyNames.ControlType, ControlType.Button.Name);
}
public virtual System.Windows.Media.Color AnimatedStartColor {
get { return ((System.Windows.Media.Color)(this.GetProperty(AnimatedButton.PropertyNames.AnimationStartColor))); }
}

    public virtual System.Windows.Media.Color AnimatedEndColor {
get { return ((System.Windows.Media.Color)(this.GetProperty(AnimatedButton.PropertyNames.AnimationEndColor))); }
}

    public virtual Duration AnimationDuration {
get { return ((Duration)(this.GetProperty(AnimatedButton.PropertyNames.AnimationDuration))); }
}

    new public abstract class PropertyNames : WpfButton.PropertyNames {
public static readonly string AnimationDuration = "AnimationDuration";
public static readonly string AnimationStartColor = "AnimationStartColor";
public static readonly string AnimationEndColor = "AnimationEndColor";
}
}

 

Presto – I have a working plugin which gives me the custom WPF control’s custom properties. I can add assertions on them using Coded UI Test Builder. I can also hand-code my validation using my AnimatedButton class.

I have attached the complete code sample.

WPFCustomPropertiesSample.zip