Compiling mono

As you could read in my previous post I’m playing with mono. This is open source so any problem can actualy be fixed by you. All you need to do is make some changes to the sources and compile. A good manual is here, be sure to install libintl2 too. And after a good hour or two you’ll see this in you Cygwin console:

Some problems I ran into

  • In general don’t forget to run make clean.
  • Compilation failed: x error(s), x warnings: check your code, something is not right
  • gac directories could not be created. possibly permission issues.: remove the listed directory and try again
  • …: fork: Resource temporary unavailable.: begin all over 😦 with make clean, ./configure, make, make install
  • More to come…
Posted in Development | Tagged , , , , , , | 1 Comment

Cross platform development with mono

The DotNET framework is an open standard and mono is the implementation for multiple platforms, including Linux, MacOSX and Windows. Mono is behind on the Microsoft dotNET framework, but there might be just enough features for your program to run on it.
You can develop with MonoDevelop which is my preferred development environment on MacOSX, a plugin is available to debug from Visual Studio and the Moma tool analyses your assemblied for mono compatibility.
A complete toolbox for every developer with C# knowledge, because there is no VB.net support.

Posted in Development | Tagged , , , , | 1 Comment

Trace to Windows EventLog

Windows 7 Event Viewer Icon

In dotNET we use the System.Diagnostics.Trace and some TraceListerner implementation to log information, warnings and errors. My applications use the Windows Eventlog with the EventLogTraceListener. But what if your custom EventSource is not available and your user has no administrative privileges? This problem emerged yesterday with a hard crash of my application.

The TraceListener was added from code so I added some extra logic to prevent the application from crashing. It checks wether it can trace to the EventSource by writing to the EventLogTraceListener. This tries to create the eventsource if it doesn’t exist.

using System.Diagnostics;

/// ... somewhere in my startup code ...
var eventLog = new EventLog("Application");
// convention: use the name of the application as the source
eventLog.Source = System.Reflection.Assembly.GetEntryAssembly().GetName().Name;
eventloglistener = new EventLogTraceListener(eventLog);
eventloglistener.Filter = new EventTypeFilter(SourceLevels.Error);

try
{
    // Try to write to it, if the source exists this will succeed else the framework
    // will try to create it which can result in an exception on insufficient privileges
    eventloglistener.WriteLine("Testing eventsource is available");
    // We're okay add to the listeners
    Trace.Listeners.Add(eventloglistener);
}
catch (Exception ex)
{
    eventloglistener = null;
    // fallback scenario: notify user about missing eventsource
}

Almost the same code can be used to check the TraceListeners from the configuration file. Just try to trace some text from within a try-catch block.

Posted in Development | Tagged , , , , , , | Leave a comment

Windows 8 developer preview

Windows 8 is released as a preview version for developers. The post on Scott Hanselman‘s blog inspired me to download and install it.
I started by creating the USB stick version of the image but ran into some trouble. After the USB/DVD download tool completed the following exception was shown.Windows 7 USB/DVD download tool error message
Turns out you need a x64 operating system when you try this with the x64 Windows 8 image. After running the USB/DVD download tool again from my x64 system everything worked out.
The installation was easy following the guide from the post above. After completion I installed the Windows 7 video driver and everything works like a charm. Here is a video of my installation.

Posted in Conference, Development | Tagged , , , , , , , , | Leave a comment

Custom AutomationPeer classes

When you use custom controls in your silverlight application, you should implement custom AutomationPeer classes. These AutomationPeer classes will be used in your unittests. Below some different flavours I use in my project.

  • Inherited, when you inherit from a control that already has an AutomationPeer you can redirect everything to that implementation.
  • /// <summary>
    /// Special button that inherits from the Button control
    /// </summary>
    public class SpecialButton : System.Windows.Controls.Button
    {
       // your magic happens here
    }
    
    /// <summary>
    /// Exposes SpecialButton types to UI automation.
    /// </summary>
    public class SpecialButtonAutomationPeer : System.Windows.Automation.Peers.ButtonAutomationPeer
    {
       /// <summary>
       /// Initializes a new instance of the <see cref="SpecialButtonAutomationPeer"/> class.
       /// </summary>
       /// <param name="owner">The owner.</param>
       public SpecialButtonAutomationPeer(SpecialButton owner) : base(owner)
       {
       }
    }
    
  • Wrapped, when you wrap a control that already has an AutomationPeer you can redirect everything to that implementation.
  • /// <summary>
    /// Special textbox that wraps a TextBox control 
    /// </summary>
    public class SpecialTextBox
    {
       // internal to expose within the assembly
       // protected to expose to controls who inherit this SpecialTextBox
       internal protected System.Windows.Controls.TextBox _textBox;
       // your magic happens here
    }
    
    /// <summary>
    /// Exposes SpecialTextBox types to UI automation.
    /// </summary>
    public class SpecialTextBoxAutomationPeer : System.Windows.Automation.Peers.TextBoxAutomationPeer
    {
       /// <summary>
       /// Initializes a new instance of the <see cref="SpecialTextBoxAutomationPeer"/> class.
       /// </summary>
       /// <param name="owner">The owner.</param>
       public SpecialButtonAutomationPeer(SpecialTextBox owner) : base(owner._textBox)
       {
       }
    }
    
  • Composite 1, when you use multiple controls that already have an AutomationPeer you can redirect everything to that implementation, but you need to direct this. You expose an AutomationPeer for every control on the composite control
  • /// <summary>
    /// Special time control that is a composite of two ComboBox controls
    /// </summary>
    public class SpecialTimeControl : System.Windows.Controls.Control
    {
       // internal to expose within the assembly
       // protected to expose to controls who inherit this SpecialTimeControl
       internal protected ComboBox _hoursComboBox;
       internal protected ComboBox _minutesComboBox;
       // your magic happens here
    }
    
    /// <summary>
    /// Exposes ComboBoxAutomationPeer types to UI automation.
    /// </summary>
    public class SpecialTimeControlAutomationPeer : System.Windows.Automation.Peers.ComboBoxAutomationPeer
    {
       /// <summary>
       /// Enumeration for selecting the timepart control
       /// </summary>
       public enum TimePartControl
       {
          /// <summary>
          /// Control for providing the Hours value
          /// </summary>
          Hours = 0,
          /// <summary>
          /// Control for providing the Minutes value
          /// </summary>
          Minutes = 1
       }
    
       /// <summary>
       /// Initializes a new instance of the <see cref="SpecialTimeControlAutomationPeer"/> class.
       /// </summary>
       /// <param name="owner">The owner.</param>
       /// <param name="control">The part of the control to expose.</param>
       public SpecialTimeControlAutomationPeer(SpecialTimeControl owner, TimePartControl control) : base(SelectControl(owner, control))
       {
       }
    
       /// <summary>
       /// Selects the control.
       /// </summary>
       /// <param name="owner">The owner.</param>
       /// <param name="selection">The selection.</param>
       /// <returns></returns>
       private static ComboBox SelectControl(SpecialTimeControl owner, TimePartControl selection)
       {
          ComboBox result = null;
          switch (selection)
          {
             case TimePartControl.Hours:
                result = owner._hoursComboBox;
                break;
             case TimePartControl.Minutes:
                result = owner._minutesComboBox;
                break;
          }
          return result;
       }
    }
    
    // example: set the hour part of the time control to 10
    var hoursComboBoxPeer = new SpecialTimeControlAutomationPeer(ctrl, SpecialTimeControlAutomationPeer.TimePartControl.Hours);
    var hour = "10";
    var hoursComboBoxSelectionItem = (ISelectionItemProvider)hoursComboBoxPeer.GetChildren()
        .Where(x => x.GetName().Equals(hour))
        .First()
        .GetPattern(PatternInterface.SelectionItem);
    hoursComboBoxSelectionItem.Select();
    
  • Composite 2, when you use multiple controls that already have an AutomationPeer you can redirect everything to that implementation, but you need to direct this. You implement the provider interface on the custom AutomationPeerclass.
  • /// <summary>
    /// Exposes SpecialTimeControl types to UI automation.
    /// </summary>
    public class SpecialTimeControlAutomationPeer : System.Windows.Automation.Peers.SelectorAutomationPeer, 
                                                    System.Windows.Automation.Provider.IValueProvider
    {
        protected System.Windows.Automation.Peers.ComboBoxAutomationPeer _hoursComboBoxAutomationPeer;
        protected System.Windows.Automation.Provider.IValueProvider _hoursValueProvider;
        protected System.Windows.Automation.Peers.ComboBoxAutomationPeer _minutesComboBoxAutomationPeer;
        protected System.Windows.Automation.Provider.IValueProvider _minutesValueProvider;
    
        /// <summary>
        /// Initializes a new instance of the <see cref="SpecialTimeControlAutomationPeer"/> class.
        /// </summary>
        /// <param name="owner">The owner.</param>
        public SpecialTimeControlAutomationPeer(SpecialTimeControl owner) : base(owner._hoursComboBox)
        {
            // construct the AutomationPeer and IValueProvider objects that will do all the actual work
            _hoursComboBoxAutomationPeer = new System.Windows.Automation.Peers.ComboBoxAutomationPeer(owner._hoursComboBox);
            _hoursValueProvider = (System.Windows.Automation.Provider.IValueProvider)_hoursComboBoxAutomationPeer.GetPattern(System.Windows.Automation.Peers.PatternInterface.Value);
            _minutesComboBoxAutomationPeer = new System.Windows.Automation.Peers.ComboBoxAutomationPeer(owner._minutesComboBox);
            _minutesValueProvider = (System.Windows.Automation.Provider.IValueProvider) _minutesComboBoxAutomationPeer.GetPattern(System.Windows.Automation.Peers.PatternInterface.Value);
        }
    
        /// <summary>
        /// Gets the control pattern for the <see cref="T:System.Windows.Controls.Primitives.Selector"/> that is associated with this <see cref="T:System.Windows.Automation.Peers.SelectorAutomationPeer"/>.
        /// </summary>
        /// <param name="patternInterface">One of the enumeration values.</param>
        /// <returns>
        /// The object that implements the pattern interface, or null if the specified pattern interface is not implemented by this peer.
        /// </returns>
        public override object GetPattern(System.Windows.Automation.Peers.PatternInterface patternInterface)
        {
            // this class implements the IValueProvider so return it
            if (patternInterface == System.Windows.Automation.Peers.PatternInterface.Value) return this;
            else return base.GetPattern(patternInterface);
        }
    
        /// <summary>
        /// Gets a value that indicates whether the value of a control is read-only.
        /// </summary>
        /// <returns>true if the value is read-only; false if it can be modified. </returns>
        public bool IsReadOnly
        {
            get 
            { 
                return _hoursValueProvider.IsReadOnly || _hoursValueProvider.IsReadOnly;
            }
        }
    
        /// <summary>
        /// Sets the value of a control.
        /// </summary>
        /// <param name="value">The value to set. The provider is responsible for converting the value to the appropriate data type.</param>
        public void SetValue(string value)
        {
            // value should be a datetime
            var date = DateTime.Parse(value);
            // get the parts
            var hour = date.Hour.ToString();
            var minute = date.Minute.ToString("00");
            // find the item in the children that matches
            // the value for hour in the date
            var hoursComboBoxSelectionItem = 
                (System.Windows.Automation.Provider.ISelectionItemProvider)
                _hoursComboBoxAutomationPeer.GetChildren()
                .Where(x => x.GetName().Equals(hour))
                .First() // throws an expection if not found
                .GetPattern(System.Windows.Automation.Peers.PatternInterface.SelectionItem);
            // select the hour
            hoursComboBoxSelectionItem.Select();
            // find the item in the children that matches
            // the value for minute in the date
            var minutesComboBoxSelectionItem = 
                (System.Windows.Automation.Provider.ISelectionItemProvider)
                _minutesComboBoxAutomationPeer.GetChildren()
                .Where(x => x.GetName().Equals(minute))
                .First() // throws an expection if not found
                .GetPattern(System.Windows.Automation.Peers.PatternInterface.SelectionItem);
            // select the minute
            minutesComboBoxSelectionItem.Select();
        }
    
        /// <summary>
        /// Gets the value of the control.
        /// </summary>
        /// <returns>The value of the control.</returns>
        public string Value
        {
            get 
            {
                var hour = int.Parse(_hoursValueProvider.Value);
                var minute = int.Parse(_minutesValueProvider.Value);
                // use defaults for the year, month, day and seconds
                var date = new DateTime(2000, 1, 1, hour, minute, 0);
                return date.ToString();
            }
        }
    }
    
    // example: set the complete time to the current time
    var specialTimeAutomationPeer = new SpecialTimeControlAutomationPeer(ctrl);
    var specialTimeValueProvider = specialTimeAutomationPeer.GetPattern(System.Windows.Automation.Peers.PatternInterface.Value);
    specialTimeValueProvider.SetValue(DateTime.Now); // uses the current time
    

The choice between the two composite controls is up to you. Maybe you need both. The difference is the place where the controls are set. In composite 1 this is done in your testcode which gives you the possibility to do some wrong inputs. In composite 2 the code is kept out of the testcode which provides more robust tests.

Posted in Test | Tagged , , , , , | 6 Comments