torsdag 9. juni 2011

UITypeEditor

When you add a property to a class, the Visual Studio developer environment automatically adds this to the properties pane as a string.

Sometimes we would like a choose this from a graphical user interface. This can be done by using UITypeEditor. I've created a property in my class and wanted the user to be able to choose a type from the same assembly (which implements IHandler). Here is the code:

namespace Birol.UIType
{
    internal class InterfaceEditor : UITypeEditor
    {
        //we have to override EditValue method to tell Visual Studio how to behave on edit.
        public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
        {
            Type returnValue = null;
            var service = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
            if (service != null)
            {
                var types = new List();
                
                var a = Assembly.GetExecutingAssembly();
                var types = a.GetTypes();

                //we loop through each type and check if it implements IHandler
                foreach (var t in types)
                {
                    if (typeof(IHandler).IsAssignableFrom(t) && !t.IsAbstract && !t.IsInterface)
                    {
                        types.Add(t);
                    }
                }

                //We display a listbox to the user with the values he/she can choose from.
                var list = new ListBox();
                list.Click += new EventHandler((sender, args) => service.CloseDropDown());
                list.Items.AddRange(types.ToArray());
                service.DropDownControl(list);
                if (list.SelectedIndices.Count == 1)
                {
                    returnValue = list.SelectedItem as Type;
                }
            }
            return returnValue;
        }

        //override to tell visual studio which editstyle to use.
        public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
        {
            return UITypeEditorEditStyle.DropDown;
        }
    }
}

And here is how you create the property:

[Browsable(true),
         Editor(typeof (InterfaceEditor), typeof (UITypeEditor)),
         Category("Behavior"),
         DescriptionAttribute("The name of the class that should be executed when clicked.")]
        public Type Executer { get; set; }

Here is the result:

mandag 6. juni 2011

Enums with string values

I have always thought that enums are pretty annoying in .NET. The problem is that they can only hold integer values, which means that it is difficult to map them to database columns which is of type VARCHAR/CHAR.

One way of solving this is with custom attributes and class extensions.

Here is the code:

First we create an attribute to hold the string value for the enum:
    public class StringValueAttribute : Attribute
    {
        /// 
        /// Holds the stringvalue for a value in an enum.
        /// 
        public string StringValue { get; protected set; }

        /// 
        /// Constructor used to init a StringValue Attribute
        /// 
        /// 
        public StringValueAttribute(string value)
        {
            StringValue = value;
        }
    }

Next we use this attribute in an enum:
    public enum Country
    {
        [StringValue("N")]
        Norway,
        [StringValue("DK")]
        Denmark,
        [StringValue("GB")]
        England
    }

The last thing we need to do is create an extension method for the Enum class and one extension method for the string class:
    public static class EnumExtensions
    {
        public static string GetStringValue(this Enum value)
        {
            // Get the type
            var type = value.GetType();

            // Get fieldinfo for this type
            var fieldInfo = type.GetField(value.ToString());

            // Get the stringvalue attributes
            var attribs = fieldInfo.GetCustomAttributes(
                typeof(StringValueAttribute), false) as StringValueAttribute[];

            // Return the first if there was a match.
            return attribs != null && attribs.Length > 0 ? attribs[0].StringValue : string.Empty;
        }
    }

    public static class StringExtensions
    {
       public static Enum GetEnumValue(this string value, Type enumType)
        {
            // Get the type
            var type = enumType;

            var fieldInfos = type.GetFields();

            foreach (var fieldInfo in fieldInfos)
            {
                var attribs = fieldInfo.GetCustomAttributes(typeof(StringValueAttribute), false) as StringValueAttribute[];
                if (attribs != null && attribs.Length > 0 && attribs[0].StringValue == value)
                {
                    var enumValue = (int)fieldInfo.GetValue(enumType);
                    return (Enum)Enum.ToObject(enumType, enumValue);
                }

            }

            if (Enum.IsDefined(enumType, value))
            {
                return (Enum)Enum.Parse(enumType, value);
            }
            
            throw new FaultException(value + " is not a valied object in class " + enumType.AssemblyQualifiedName);
        }
    }

Here is how to use it:
   //From string to enum
   string s = "N";
   Country c = (Country)s.GetEnumValue(typeof(Country));

   //From enum to string
   Country c = Country.Norway;
   string s = c.GetStringValue();

søndag 29. mai 2011

Microsoft UI Automation

A colleague of mine (from earlier) once asked me what the operator ++ did. YES, it was VERY funny and we all laughed. The reason it was funny was that he had been programming for several years. He had been using variable = variable + 1 instead.
With this in mind I looked at the System.Windows.Automation namespace in .Net framework 4.0. This is the Microsoft UI Automation library which is great to use when automating testing of the user interface.

I created a library that could put away the use of ++ :), by using.... calc.exe (calculator in windows) !!! The program itself is very simple, but the main purpose was to use Microsoft UI Automation, and it works great. Here is the code:

        private int AddOne(int number)
        {
            using (var p = Process.Start("calc.exe"))
            {
                //allow time to startup
                System.Threading.Thread.Sleep(500);
                var calcWindow = AutomationElement.FromHandle(p.MainWindowHandle);

                foreach (char c in number.ToString())
                {
                    PushButton(calcWindow, c.ToString());
                }

                PushButton(calcWindow, "Add");
                PushButton(calcWindow, "1");
                PushButton(calcWindow, "Equals");

                int result = GetResult(calcWindow);
                p.Kill();
                return result;
            }
        }

        private int GetResult(AutomationElement window)
        {
            var controls = window.FindAll(TreeScope.Descendants, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Text));

            foreach (AutomationElement control in controls)
            {
                int result;
                if (int.TryParse(control.Current.Name,out result))
                    return result;
            }

            return 0;
        }

        private AutomationElement GetButton(AutomationElement searchIn, string searchFor)
        {
            var buttons = searchIn.FindAll(TreeScope.Descendants, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button));

            foreach (AutomationElement button in buttons)
            {
                if (button.Current.Name == searchFor)
                    return button;
            }

            return null;
        }

        private void PushButton(AutomationElement window, string buttonName)
        {
            var button = GetButton(window, buttonName);
            if (button != null)
                (button.GetCurrentPattern(InvokePattern.Pattern) as InvokePattern).Invoke();
        }
    }

fredag 20. mai 2011

First entry

Hi everyone!

This is my first blog entry. In the future I will be posting tips and tricks regarding .NET programming in Visual Studio, BizTalk, SqlServer and other geek stuff :) The main purpose of the blog is for me to remember what I have been working with.

Have you ever been stuck with a problem, and knew that you had solved the exact same problem just a couple of months earlier, but you were not able to find that little piece of fantastic code? Well... no more.