Showing posts with label User Experience. Show all posts
Showing posts with label User Experience. Show all posts

Wednesday, February 18, 2015

The Feature Flags Pattern





I was listening to Episode 1101 of the podcast Dot Net Rocks. Jez Humble was talking about the concept of Feature Toggles or Feature Flags. Feature Switches? While the term has some opinionated definitions, the concept that I found most interesting was the idea of deploying software with the new features initially disabled, or switched off by some mechanism. After you think the feature is ready for production, switch on the feature. If there is an issue, you don't have to roll back the version or deploy another release, just switch the feature back off again and replace its .dll. Didn't get enough debug information? Switch the feature back on and let a few crash reports trickle in and then switch it back off. If you feature is particularly processor or network intensive, you can perform load testing by slowly releasing the features to select clients or only part of the population/userbase.

While I personally choose an SQL table for my approach to storing the toggle switches (internal business app), one could use the application's .config file. An application could pull the settings from a .config file on a networked drive as a way of controlling multiple application instances by making one changed to a centralized location. Below I show a minimalist implementation by creating a Dictionary from the <appSettings> in a App.config file.

Behold:


public static Dictionary<string, bool> GetFeatureFlags()
{
  return ConfigurationManager.AppSettings.AllKeys.ToDictionary(s => s, IsFlagSet);
}

public static bool IsFlagSet(string settingName)
{
  bool result = false;
  bool.TryParse(ConfigurationManager.AppSettings[settingName], out result);
  return result;
}

Of course with a dictionary you have to be careful that you don't try an access a column that does not exist with the indexer, so you might be better off using IsFlagSet(string), which will never throw. Although this is of limited use (AppSettings is already a NameValueCollecion), perhaps you can make use of this generic function I wrote that uses generics to convert AppSettings into a dictionary with the type of the value being the generic:


public static Dictionary<string, T> GetDictionary<T>()
{
 return ConfigurationManager.AppSettings.AllKeys.ToDictionary<string, string, T>(s => s, GetSetting<T>);
}

public static T GetSetting<T>(string settingName)
{
  try
  {
    T result = (T) Convert.ChangeType(
      ConfigurationManager.AppSettings[settingName],
      typeof (T)
    );
    if (result != null)
    {
      return result;
    }
  }
  catch { }

  return default(T);
}

Please note that swallowing an exception ("catch { }") is typically considered poor form. In this particular scenario, I am aware of the possible exceptions that can be thrown by this code and I want the code to return the default(T) in this scenario and never throw.



Wednesday, February 4, 2015

EditLabel UserControl



EditLabel is editable Label control, who's text can be modified at run-time by double-clicking on it. Under the hood, it contains a Label control and TextBox control. It works like a Label control until you double-click it with the mouse. When double-clicked it enters 'edit-mode' where a TextBox overlays the Label. The control will AutoSize to the characters you type in the TextBox, updating the Label's size at the same time. You can leave the control's edit mode by hitting either enter, the escape key, or letting the control lose focus. After editing, the control acts like a label again, with the updated text. You can check out the code for the EditLabel project here on my GitHub.

The EditLabel isn't too interesting by itself, but I wanted to blog about it for all the interesting attributes that I never knew about until I started getting into designing controls, and controlling how controls are displayed in the designer window in visual studio.

The first thing my EditLabel control needed was and event that the parent form could subscribe to know when the text changed. Creating the event simply isn't enough. If you want the event to show up in the Visual Studio's Form Designer when you click on events, you need to add the Browsable and EditorBrowsable attribute. This will make is show up in the designer. You can control the description that appears as well as what category it shows up under when viewing events/properties in the Categorize view as opposed to Alphabetical view by using the Description and Category attributes respectively:

[Category("Property Changed")]
[Description("Event raised when the value of the Text property is changed on Control.")]
[Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
public new event EventHandler TextChanged;

There is also the notion of default events. That is, the event for which a handler is added when you double click the control in the designer. For example, when you double click a TextBox, it automatically adds the TextChanged event, instead of, say, the KeyDown event. To make an event the default event, add the DefaultEvent attribute at the control's class-level declaration:

[DefaultEvent("TextChanged")]
public partial class EditLabel : UserControl
{
   ...

Another thing I wanted was the Text property. Like a Label or a TextBox control, I wanted a public Text property that could be edited at design time. However, every time I re-built the project, the text would get reset to the default. As it turns out, if you want modifications to properties to be persisted, it must be serialized to the MainForm.Designer.cs, or whatever the auto-generated Designer.cs file is. In order to tell the designer to serialize changes made at design time to Designer.cs file, you have to add the DesignerSerializationVisibility attribute above the property. Here is the attributes and declaration for the Text property:

[Category("Appearance")]
[Description("The text associated with the control.")]
[Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public override string Text
{
   get { return ctrlLabel.Text; }
   set { ChangeText(value); }
}

You can view the full EditLabel.cs here, or view the entire EditLabel project here.



Thursday, January 22, 2015

Graceful Console Exit



When writing console apps sometimes you want to delay the closing of the console window to give the user time to read the output. Often, if something went wrong, I would simply report the error to the standard output and immediately exit the application. However that did not work too well for my users; the exit message was not displayed long enough for them to read so they knew how to correct the issue. What I needed was something that give a user enough time to read the output, but not prevent the process from exiting if it was being ran as a scheduled/automated task. The solution I came up with was a countdown timer that would block execution from proceeding until it counted back from some number to zero.

Lets view the code, shall we:

public static void CountdownTimer(int Seconds = 5)
{
    Console.ResetColor();
    Console.WriteLine(Environment.NewLine);
    Console.Write("The application will now terminate...   ");

    if (Seconds < 1) return;
    if (Seconds > 9) Seconds = 9;

    for (int counter = Seconds * 10; counter > 0; counter--)
    {
        if (Console.KeyAvailable)
            return;

        if (counter % 10 == 0)
            Console.Write("\b{0}", (counter / 10));

        System.Threading.Thread.Sleep(100);
    }
}

I print each number as the timer counts down. Each time I print a new number, I place a backspace "\b" before it to erase the previous number. To avoid having to keep track how many character a digit prints to use the same number of backspaces, I just kept the function simple by limiting the number of seconds to a max of 9.
I check for Console.KeyAvailable to detect key strokes to skip the rest of the countdown and exit immediately. The reason I did 10 Sleeps of 100ms per second was to make the exit upon key press more responsive.

Saturday, September 27, 2014

Resize form to match the contents of DataGridView



Sometimes the sole purpose of a Form is to display a DataGridView. In that case, you probably want the Form to automatically resize to the size of the contents in the DataGridView. I've seen solutions that loop through all the rows and add up the height, but this is ugly, and usually does not take into account margins, padding, DividerHeight and row header padding. There must be a better way...

My strategy is to temporarily undock the DataGridView, set AutoSize to true, then capture the DataGridView's Size at that point, then restore the Dock and AutoSize property. Then use the captured size to resize the Winform:


// Within the Form class
private void AutoSizeFormToDataGridView()
{
 Size contentsSize = GetDataGridViewContentsSize();
 this.ClientSize = contentsSize;
}

protected Size GetDataGridViewContentsSize()
{
 DockStyle dockStyleSave = dataGridView1.Dock;
 dataGridView1.Dock = DockStyle.None;
 dataGridView1.AutoSize = true;
 
 Size dataContentsSize = dataGridView1.Size;
 
 dataGridView1.AutoSize = false;
 dataGridView1.Dock = dockStyleSave;
 return dataContentsSize;
}


Or alternatively you can define this as an extension method:

public static Size GetContentsSize(this DataGridView dataGrid) { //...


Enjoy!

Sunday, June 23, 2013

Gracefull error handling with a global exception handler




Every published C# application should have graceful error handling. Here I show you the implementation of a global exception handler using ThreadExceptionEventHandler.

First, you have to add System.Threading to both your Program.cs and Mainform.cs:
// Program.cs and Mainform.cs
using System.Threading;

Then add an event handler to Application.ThreadException:
// Program.cs
// static class Program {
//  private static void Main(string[] args) {
Application.ThreadException += new ThreadExceptionEventHandler(MainForm.MyExceptionHandler);
// Application.Run(new MainForm());

Or, if you are writing a console app, add an event handler to AppDomain.UnhandledException:
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyExceptionHandler);

Then add the exception handler body:
// Mainform.cs
public static void MyExceptionHandler(object sender, ThreadExceptionEventArgs e)
{
   MessageBox.Show(e.Exception.Message,"Error",MessageBoxButtons.OK,MessageBoxIcon.Error);
}

The example here simply shows a message box, but an even more graceful approach would be to log all the unhanded exceptions to a log file. That way, the errors are transparent to the user, but the developer still has access to detailed debug information.

Here is the full code:
Program.cs
MainForm.cs