30 April 2011

ASP.NET / MVC - Localization

Here's how I localized an ASP.NET MVC3 application.

The controller

the master layout page contained some language links like this one:

@Html.RouteLink("Nederlands",
                 new { Controller = "Home",
                       Action = "Language",
                       culture = "nl-BE" })

They refer to a simple action:

public ActionResult Language(string culture) {
  App.SetCulture(culture);
  return RedirectToAction("Index");
}

The model

I prefer handling the actual setting of the culture in the model, so I created a static class called App containing these methods:

public static void Store(string key, object value) {
  if (HttpContext.Current.Session != null)
    HttpContext.Current.Session[key] = value;
}

public static object Retrieve(string key) {
  return HttpContext.Current.Session == null ?
         null :
         HttpContext.Current.Session[key];
}

public static void SetCulture(string cultureName) {
  Store("culture", cultureName);
  Thread.CurrentThread.CurrentCulture =
  Thread.CurrentThread.CurrentUICulture =
  CultureInfo.GetCultureInfo(cultureName);
}

Very important: the thread culture must be set again for every request. But a .css file or image files are also a requests. For those requests however, the session object does not exist. Hence, the null-tests.

Global.asax

So the culture must be set for each request. You could do it in the Initialize method of each controller, or in just one place: Global.asax. I put it in the Application_AcquireRequestState method, because from this method on the session object is available. From there, it's just a simple call:

App.SetCulture((string)App.Retrieve("culture") ?? "nl-BE");

24 April 2011

C# - Convert hex color to RGB

To convert a hexadecimal color value like #FF00FF to a RGB color value, I wrote this function:

string color = "#FF00FF"; //This would be a parameter
if (color.StartsWith("#"))
  color = color.Remove(0, 1);
byte r, g, b;
if (color.Length == 3) {
  r = Convert.ToByte(color[0] + "" + color[0], 16);
  g = Convert.ToByte(color[1] + "" + color[1], 16);
  b = Convert.ToByte(color[2] + "" + color[2], 16);
}
else if (color.Length == 6) {
  r = Convert.ToByte(color[0] + "" + color[1], 16);
  g = Convert.ToByte(color[2] + "" + color[3], 16);
  b = Convert.ToByte(color[4] + "" + color[5], 16);
}
else {
  throw new ArgumentException("Hex color " + color + " is invalid.");
}
return new Color.FromArgb(255, r, g, b);

22 April 2011

Visual Studio / ASP.NET - Default browser for debug

Here's how te set the default browser that will start when debugging a web application in Visual Studio:
  • Right click one of the .aspx pages,
  • Choose Browse With...,
  • Select the desired browser,
  • Click Set as Default.
A very convienient alternative is this Visual Studio extension.

    ASP.NET - Output XML file

    To download an XML file from an ASP.NET website, for instance after clicking a button, you can use the following sort of code. This one will retrieve a DataTable, and offer it as an XML file to download:

    using (MemoryStream stream = new MemoryStream()) {
      XmlTextWriter xml = new XmlTextWriter(stream, Encoding.UTF8);
      xml.WriteStartDocument();
      xml.WriteStartElement("output");
    
      string value = string.Empty;
      foreach (DataRow row in data.Rows) {
        xml.WriteStartElement("row");
        foreach (DataColumn col in data.Columns) {
          value = row[col].ToString();
          xml.WriteElementString(col.ColumnName, value);
        }
        xml.WriteEndElement();
      }
    
      xml.WriteEndElement();
      xml.WriteEndDocument();
      xml.Flush();
    
      byte[] bytes = stream.ToArray();
      Response.Clear();
      Response.AppendHeader("Content-Disposition", "filename=Output.xml");
      Response.AppendHeader("Content-Length", bytes.Length.ToString());
      Response.ContentType = "application/octet-stream";
      Response.BinaryWrite(bytes);
      xml.Close();
    }
    

    19 April 2011

    Azure - Supported data types in storage tables

    In Windows Azure, to insert an object in a table, you do this:

    TableServiceContext tableContext = tableClient.GetDataServiceContext();
    tableContext.AddObject("Products",
                           new Product() { PartitionKey = "SynProd",
                                           RowKey = Guid.NewGuid().ToString(),
                                           Name = "EGS Database Tool 1.0.2.0",
                                           PurchasePrice = 1400.50m });
    tableContext.SaveChanges();
    

    That gave me the error
    One of the request inputs is not valid
    because of the decimal value in the object. Those are not yet supported in tables.
    When I changed it into a double value it worked.

    Here are the currently supported types in Azure Table Service:

    ADO.NET               CLR          Detail
    Edm.Binary            byte[]       Max. 64 kB
    Edm.Boolean           bool
    Edm.DateTime          DateTime     64-bit UTC 01 jan 1601 0:00 - 31 dec 9999
    Edm.Double            double       64-bit
    Edm.Guid              Guid         128-bit
    Edm.Int32             int          32-bit
    Edm.Int64             Int64        64-bit
    Edm.String            string       Max. 64 kB, UTF-16 encoded
    

    12 April 2011

    Silverlight - Full screen mode

    Setting a Silverlight control to full screen mode is easy:
    App.Current.Host.Content.IsFullScreen = true;
    
    And just set it to false to reverse it.

    WPF / XAML - Using system colors

    Binding a system color to a property in XAML is done like this:
    Foreground="{x:Static SystemColors.HighlightBrush}"
    

    A reference about these system colors can be found here.

    WPF / Silverlight - Custom tooltip

    Giving a control a customized tooltip in WPF or Silverlight is quite easy:
    <Image Source="Help.png" Margin="4 2" Cursor="Hand" Stretch="None">
      <Image.ToolTip>
        <Border CornerRadius="4" Padding="2">
          <StackPanel Orientation="Vertical">
            <TextBlock x:Name="txtTitle" Margin="1" FontWeight="Bold" />
            <TextBlock x:Name="txtText" Margin="1" />
          </StackPanel>
        </Border>
      </Image.ToolTip>
    </Image>
    

    Moreover, by adding
    ToolTipService.ShowDuration="60000"
    
    to the control owning the tooltip, the tooltip will be displayed a whole minute instead of the default 5 seconds.

    WPF - Dependency property for databinding

    To databind on a property of a user control this property needs to be a dependency property. The following is how I implemented that:

    public partial class HelpUserControl : UserControl {
      public static readonly DependencyProperty HelpTextProperty =
        DependencyProperty.Register("HelpText",
                                    typeof(string),
                                    typeof(HelpUserControl),
                                    new PropertyMetadata(OnHelpTextChanged));
      public string HelpText {
        get { return (string)this.GetValue(HelpTextProperty); }
        set { this.SetValue(HelpTextProperty, value); }
      }
    
      private static void OnHelpTextChanged(
                          DependencyObject target,
                          DependencyPropertyChangedEventArgs e) {
        (target as HelpUserControl).imgIcon.ToolTip = e.NewValue.ToString();
      }
    }
    

    11 April 2011

    Excel - Cell colors and windows high contrast theme

    I use my Windows 7 with a high contrast theme, which is great apart from some minor problems. One such problem is Excel (2010) that won't display fore- and background colors anymore. First change Windows'high contrast mode with the key combination L-SHIFT + L-ALT + PRT SCR. This doesn't have an immediate effect (at least for me). Then, in Excel, go to File > Options > General > User Interface options, select a Color scheme and click OK. Doing so will change Excels'interface and allow fore- and background colors once more.