22 December 2011

JS - Optional function parameters

Sometimes you want to call the same JavaScript function with a different number of parameters, to replicate the overloading we use in, for instance, .NET. This is how to do it:
function setMenu(param1, param2){
  if(param2 === undefined){
    param2 = -1;
  }
  //Code
}
You can call this function in multiple ways:
setMenu(0, 5);
setMenu(0); //Param2 will be set to '-1' by the function
And both will work.

20 December 2011

SL Toolkit chart - clickable legend items

The Silverlight Toolkit chart allows for click-though by setting IsSelectionEnabled to true on the series, and attaching the SelectionChanged event. Now you can click on bars or pie slices, and interact on that.

But what if you want to also make the legend beside the chart clickable. That's not supported out of the box. You do this by changing the Legend Items template.

The template

Define a template like the following for the legend items. I've put this as a resource in the Grid that contains my Chart.
<Grid.Resources>
 <Style x:Key="CategoryLegendItem" TargetType="toolkit:LegendItem">
  <Setter Property="Template">
   <Setter.Value>
    <ControlTemplate TargetType="toolkit:LegendItem">
     <StackPanel Orientation="Horizontal">
      <Rectangle Width="8" Height="8" Fill="{Binding Background}" Stroke="{Binding BorderBrush}" StrokeThickness="1" Margin="0,0,3,0" />
      <HyperlinkButton Content="{TemplateBinding Content}" Click="HyperlinkButton_Click" />
     </StackPanel>
    </ControlTemplate>
   </Setter.Value>
  </Setter>
 </Style>
</Grid.Resources>
Notice how I replaced the default Title element that displays the legend item text by a HyperlinkButton. That way it actually looks like something that can be clicked. This button also triggers the click event.

The code

First, the series LegendItemStyle must be set to the custom template. Since my chart is created in code I've put:
series.LegendItemStyle = (Style)LayoutRoot.Resources["CategoryLegendItem"]
Finally there's the HyperlinkButtons click handler.
private void HyperlinkButton_Click(object sender, RoutedEventArgs e) {
  RowPrestation row = (RowPrestation)((sender as HyperlinkButton)
                      .DataContext as PieDataPoint).DataContext;
  PieSeries series = (PieSeries)(Chart.Child as Chart).Series[0];
  series.SelectedItem = row;
}
Notice that the DataContext of the HyperlinkButton contains the PieDataPoint — in case of a pie chart — that goes with the legend item in question. And if you cast it, that points DataContext contains the bound object that was used as ItemsSource. Mine was a List<RowPrestation>.

07 December 2011

MVC/JavaScript - Serialize an object on the server to use in JavaScript using JSON

While coding a project in MVC, I wanted to serialize an object in C#, put it in the ViewBag and on the client have JQuery parse it back into an object for JavaScript to use. It can be done like this:

Server side

In the controller action, simply serialize the object this way:
ViewBag.DataFilter = new JavaScriptSerializer().Serialize(filter);
Where filter is the object.

Client side

On the client, you can parse it back like this:
//Parse
parser = document.createElement('div');
parser.innerHTML = '@(ViewBag.DataFilter)';
var DataFilter = $.parseJSON(parser.innerHTML);
//Test
alert(DataFilter.Fields[0].FieldName);
And that's all there's to it.

02 December 2011

C# - Calling a web service with GET or POST

For a dashboard I needed to connect to a Google web service and retrieve data from it. I was working in Silverlight, but Silverlights security model did not allow me to call Googles web service, so I called from an ASP.NET web service as follows:
[WebMethod]
public WebServiceResponse CallService(string name,
                                      string url,
                                      string method,
                                      string contentType,
                                      string postData) {
  WebServiceResponse result = new WebServiceResponse();
  try{
    //Convert the post data into a byte array
    //The post data is a string like "username=EGS&password=305"
    byte[] data = null;
    if (!string.IsNullOrEmpty(postData))
      data = Encoding.UTF8.GetBytes(postData);

    //Create the request and write the post data to it if any
    WebRequest request = WebRequest.Create(url);
    if (!string.IsNullOrEmpty(method))
      request.Method = method;
    if (!string.IsNullOrEmpty(contentType))
      request.ContentType = contentType;
    if (data != null) {
      request.ContentLength = (long)data.Length;
      using (Stream stream = request.GetRequestStream())
        stream.Write(data, 0, data.Length);
    }
    else
      request.ContentLength = 0L;

    //Get the response from the web service
    using (WebResponse response = request.GetResponse())
    using (StreamReader reader =
           new StreamReader(response.GetResponseStream())) {
      result.StatusCode =
             (int)(response as HttpWebResponse).StatusCode;
      result.StatusDescription =
             (response as HttpWebResponse).StatusDescription;
      result.Content = reader.ReadToEnd();
    }
  }
  catch (Exception ex) {
    result.Error = "Error: [DashboardService.CallService] " + ex.Message;
  }
  return result;
}
WebServiceResponse is a custom class with the properties StatusCode, StatusDescription, Content and Error.

23 November 2011

LINQ - On DataTable

You can transform a DataTable into a List of objects in a single statement using LINQ:
List<Customer> list = (from r in dataTable.AsEnumerable()
                       select new Customer {
                         Id      = r.Field<int>("Id"),
                         Name    = r.Field<string>("Name"),
                         Created = r.Field<datetime>("Created")
                       }).ToList();

To use AsEnumerable, you need to reference the assembly System.Data.DataSetExtensions (.NET 3.5) or include System.Data (.NET 4.5).

LINQ - List DataTable columns

How can you get a List of DataTable columns using LINQ?
The dataTable.Columns property cannot be queried with LINQ because it's a DataColumnCollection. Such a collection implements IEnumerable, but it's not a IEnumerable<DataColumn>, and therefore must be cast as such:
List<string> columnNames = (from c in dataTable.Columns.Cast<datacolumn>()
                            select c.ColumnName).ToList();

05 November 2011

Silverlight - Bindable DataGridColumn headers

When using a DataGrid in Silverlight, you might want to bind it's column headers. For localization purposes for instance. You can't bind the DataGridColumns Header property though, because it's not a dependency property. There is a work-around though, using a behaviour:

Interactivity

To use behaviour, you'll need System.Windows.Interactivity.dll. This one comes with Expression Blend. If you don't have that, you'll find it somewhere on the web.

The behaviour

The behaviour is in this class:
public class BindableColumnHeader : Behavior {
  public object Header {
    get { return GetValue(HeaderProperty); }
    set { SetValue(HeaderProperty, value); }
  }
  public static readonly DependencyProperty HeaderProperty = 
         DependencyProperty.Register("Header",
           typeof(object),
           typeof(BindableColumnHeader),
           new PropertyMetadata(
             new PropertyChangedCallback(HeaderBindingChangedHandler)));

  private static void HeaderBindingChangedHandler(
                      DependencyObject o,
                      DependencyPropertyChangedEventArgs e) {
    var behave = o as BindableColumnHeader;
    if (behave != null && behave.AssociatedObject != null)
      behave.AssociatedObject.Header = e.NewValue;
  }

  protected override void OnAttached() {
    if (this.AssociatedObject != null)
      this.AssociatedObject.Header = this.Header;
    base.OnAttached();
  }
}
It needs that .dll from before.

The DataGrid

To use the behaviour in the grid, you'll need both the interactivity dll (i:). and the behaviour class (synbus:). Then define a column like so:
<data:datagridtextcolumn binding="{Binding Customer}">
  <i:interaction.behaviors>
    <synbus:bindablecolumnheader header="{Binding Whatever}" />
  </i:interaction.behaviors>
</data:datagridtextcolumn>

02 November 2011

C# - Inline event handler

Sometimes an event handler is short enough for it to just put it inline, thus saving yet another method from being created. Let's say I have a custom event called OkEventHandler thats part of an object called RenameWindow. I attach the handler as follows:
renameWnd.Ok += new RenameWindow.OkEventHandler(delegate(object sender, EventArgs e) {
  //Whatever needs to be done
});
Or shorter:
renameWnd.Ok += (object sender, EventArgs e) => {
  //Whatever needs to be done
};
And even shorter:
renameWnd.Ok += delegate {
  //Whatever needs to be done
};
How much shorter can it get?
renameWnd.Ok += (sender, e) => DoOneThing();
Not much to it once you know.

27 October 2011

.NET - Resizing an image

Here's a little piece of C# code that resizes an image of any common type.
It was tested for .jpg, .png, .bmp and .gif.
using System.Drawing;
using System.Drawing.Drawing2D;
...
Image image = Image.FromFile(filePath);
if (image.Width > App.MAX_UPLOAD_IMAGE_SIZE ||
    image.Height > App.MAX_UPLOAD_IMAGE_SIZE) {
  int w = image.Width;
  int h = image.Height;
  if (w > h) {
    w = App.MAX_UPLOAD_IMAGE_SIZE;
    h = image.Height * w / image.Width;
  }
  else {
    w = image.Width * h / image.Height;
    h = App.MAX_UPLOAD_IMAGE_SIZE;
  }
  Bitmap bitmap = new Bitmap(w, h);
  Graphics g = Graphics.FromImage((Image)bitmap);
  g.InterpolationMode = InterpolationMode.HighQualityBilinear;
  g.DrawImage(image, 0, 0, w, h);
  g.Dispose();
  image.Dispose();
  (bitmap as Image).Save(filePath);
}

05 October 2011

XAML - Makes the tab headers justify on the width of the whole tab control

Take a TabControl with a row of headers on top.
How do you make those headers justify so that together they have (more or less) the same width as the control?
Like this:

The converter

You need a converter to calculate the width a TabItem should have:
public class TabJustifyConverter : IValueConverter {
  public object Convert(object value,
                        Type targetType,
                        object parameter,
                        CultureInfo culture) {
    if (value == null) {
      return 0;
    }
    else if (!(value is TabControl)) {
      throw new Exception(@"The TabJustifyConverter must
                            be supplied a TabControl.");
    }
    else {
      TabControl tab = value as TabControl;
      int count = 0;
      foreach (TabItem item in tab.Items)
        if (item.Visibility == Visibility.Visible)
          count++;
      return (tab.ActualWidth / count) - 2;
    }
  }

  public object ConvertBack(object value,
                            Type targetType,
                            object parameter,
                            CultureInfo culture) {
    throw new NotImplementedException();
  }
}

The XAML

In XAML, give the TabControl a name.
Then bind each TabItem's width to this control and use the converter:
<controls:TabItem x:Name="tabCustomer"
          Header="Customer"
          Width="{Binding ElementName=tabControl,
                          Converter={StaticResource TabJustifyConverter}}">
I tried putting that in a resource, but kept getting a "cannot set read-only property"-exception.

26 September 2011

HTML - Fix the 'click to activate and use this control' browser behavior

In recent years browsers require you to click embedded HTML objects before they can become active. Opera will display a tooltip with the message 'Click to activate and use this control' when you hover over one before you clicked it. This behavior can be corrected though, like this:

Create a JavaScript file — I called it FixActivate.js — and put this in it:
var objects = document.getElementsByTagName("object");
for (var i = 0; i < objects.length; i++) {
  objects[i].outerHTML = objects[i].outerHTML;
}
Then, at the bottom of any HTML page containing embedded objects, include this file like so:
<script src="FixActivate.js" type="text/javascript"></script>
Now when the page is loaded, the embedded objects are immediately active.

18 September 2011

WPF - Bind to a property in code-behind

In some case, like when you have a ComboBox inside a DataTemplate, you can't set a property, the ItemsSource in this case, from code-behind. You have to use a binding to set this property, and you can like this:

In code-behind, create a public property and set that instead:
public BindingList ProductList { get; private set; }

Then use a binding to that property to set the property of the element:
<DataTemplate>
  <this:ComboBox
        ItemsSource="{Binding ProductList,
        RelativeSource={RelativeSource  Mode=FindAncestor,
        AncestorType={x:Type this:ucStoreVisit}}}" />
</DataTemplate>

And it'll work!

15 September 2011

.NET - Output an exception including it's inner exceptions

Often when outputting an exception message, you get "see inner exception" or "one or more errors occured" for an aggregate exception. It would be convenient to, when outputting error messages, you get those attached. This extension does that. It keeps going down the inner exceptions until there are no more, and outputs them line by line:

/// <summary>
/// Returns a string that contains the message and inner messages.
/// </summary>
public static string GetFullMessage(this Exception source)
{
    var result = new StringBuilder();
    var ex = source;

    try
    {
        while (ex != null)
        {
            if (result.Length > 0)
                result.Append(Environment.NewLine);

            result.Append(ex.Message);

            //It's handy to get the actual errors when these errors occur.
            if (ex is ReflectionTypeLoadException)
            {
                result.AppendLine("Loader exceptions:");
                var typeErrors = (ex as ReflectionTypeLoadException)?.LoaderExceptions;

                if (typeErrors != null)
                    foreach (var typeError in typeErrors)
                        result.AppendLine(typeError?.Message);
            }
            else if (ex is AggregateException)
            {
                result.AppendLine("Aggregate exceptions:");
                var inner = ex.InnerException;

                while (inner != null)
                {
                    result.AppendLine(inner.Message);
                    inner = inner.InnerException;
                }
            }

            ex = ex.InnerException;
        }
    }
    catch (Exception ex2)
    {
        result.AppendLine("The following error occured in GetFullMessage:");
        result.AppendLine(ex2?.Message);
    }

    return result.ToString();
}

08 September 2011

WPF - ComboBox or DataGridComboBoxColumn with "none" option

Something trivial that's currently not possible with the ComboBox or DataGridComboBoxColumn (Toolkit) controls of WPF is adding a "none"-option on top op their dropdown without having to add it to the ItemsSource, which would be really bad design. So this is how I implemented this common requirement:

The converter

A converter is needed to make sure the none-option actualy sets the bound property to null. Without it the property would simply not change.
I created one called NullObjectConverter. It's Convert-method simply returns the value-parameter.
The ConvertBack-method does this:
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
  if (value == null || value.GetType() != targetType)
    return null;
  else
    return value;
}
I've put the resource for it in the resources of the App-class, so I don't have to do that in every XAML-file that needs it:
<this:NullObjectConverter x:Key="convNull" />

The XAML

This is my XAML for a DataGridComboBoxColumn. Notice how it uses the converter above. Important is that it's ItemsSource is a CompositeCollection composed from the none-option and the actual list of options:
<toolkit:DataGridComboBoxColumn Header="Store"
         SelectedValueBinding="{Binding Store,
                                Converter={StaticResource convNull}}">
  <toolkit:DataGridComboBoxColumn.ItemsSource>
    <CompositeCollection>
      <ListBoxItem>(none)</ListBoxItem>
      <CollectionContainer x:Name="cboStoreCollection" />
    </CompositeCollection>
  </toolkit:DataGridComboBoxColumn.ItemsSource>
</toolkit:DataGridComboBoxColumn>
The none-option will arrive in the converter as a ListBoxItem while the target type will be the type of the bound object, and therefore the converter will send NULL to the bindings' source when it's selected.

Finally, notice that the CollectionContainer that contains the actual list of options gets it's items in the code-behind, and therefore has a name:
cboStoreCollection.Collection = mStores;

31 August 2011

Javascript - Stop an event from bubbling up

In javascript, when you handle an event, allowing this event to bubble further up afterwards may cause undesirable effects.

I had some HTML that was created when clicking a butten and hidden when clicking anywhere but on that HTML itself. The buttons click event created the HTML, which was then immediately removed again because the click event bubbled on triggering the buttons parent, who then called for the removal.

The solution is to stop the event from continuing after being processed by calling this function in your own click handler:
function stopPropagation(e){
  var e = e || event; //Because of IE
  e.stopPropagation ? e.stopPropagation() : e.cancelBubble = true; //Cancel the event
}

This solution however did not seem te work in Firefox. When using jQuery though, there is one that does:
e.stopImmediatePropagation();

Javascript - Find an elements position

To find the exact position of an element in the browser window, you'd use it's offsetLeft and offsetTop properties. These report their position relative to their parent, which you'll retrieve with the offsetParent property.

Loop through the parents adding all the offsets, and you'll end up with the absolute position of the element in question.

Javascript

This function does just that:
function findPos(element){
  var left = top = 0;
  if(element.offsetParent){
    do{
      left += element.offsetLeft;
      top += element.offsetTop;
    } while(element = element.offsetParent);
  }
  return [left, top];
}

jQuery

But then, if you're using jQuery there's an even simpler way:
var pos = element.offset();
alert(pos.left + ';' + pos.top);

26 August 2011

C# - A basic localization system

For small tools I don't want to setup resource files for localization, so I developed this basic one-class system that's very easy to setup and use.

The dictionary

First off, a language enum:
public enum Language {
  Dutch = 0,
  English = 1,
  French = 2
}

Then the static class that does the rest:
public static class Dictionary {
  public static Language Language { get; set; }

  public static string Book {
    get { return GetEntry("Boek", "Book", "Livre"); }
  }

  private static string GetEntry(params string[] entries) {
    if (entries.Length > (int)Language)
      return entries[(int)Language];
    else
      return string.Empty;
  }
}

The Language parameter must be set first.
The actual literals are static properties that can be used just like they are in a resource file.
The GetEntry method helps the literals to return the right translation.

Usage

Usage of this class is very simple.
First set the language you want to use:
Dictionary.Language = theUsersLanguage;

Then use the dictionary like a resource file:
this.Title = Dictionary.Book;

12 August 2011

Extension - Format a version number

An interesting extension for a .NET-application is a one that formats a version object into a string that contains only the used parts of the version number; meaning:
  • 1.0.0.0 becomes 1.0,
  • 1.0.1.0 becomes 1.0.1.
Let's say I get the version of the application like so:
Version version = Assembly.GetExecutingAssembly().GetName().Version;
string formattedVersion = version.GetFormattedString();
This extension would then be the following:
public static string Format(this Version version)
{
    var result = new StringBuilder();
    result.Append(version.Major).Append('.').Append(version.Minor);

    if (version.Build > 0 || version.Revision > 0)
        result.Append('.').Append(version.Build);

    if (version.Revision > 0)
        result.Append('.').Append(version.Revision);

    return result.ToString();
}

11 August 2011

ASP.NET MVC - Return views from any view folder

Normally in ASP.NET MVC you return a view like this:
return View("Edit");
This view will be found in either:
  • Views/Category/Edit,
  • or Views/Shared/Edit.
You can however also return a view from another location,
like this:
return View("~\\Views\\Administration\\CategoryEdit.cshtml");

01 August 2011

IE - HTML or CSS rules specific to Internet Explorer

If you want to put some HTML or CSS rules in a page specific to Internet Explorer — I never needed this for any other browser — you can put the following in the page:
<!--[if gte IE 7]>
  <style type="text/css">
    #SearchButton{ height:23px; }
  </style>
<![endif]-->
This CSS rule would be applied only by IE7 and later.

28 July 2011

IE - Using onClick on a span element to control a textarea

I created a toolbar from span elements with background-images to control the contents of a textarea below it through the onClick event. This works fine in Opera and other browsers, but of course not in Internet Explorer. It seems IE looses the selection in the textarea when the span is clicked. There are two workarounds though:

Make the span unselectable

The first one is to simply make the span tag unselectable by adding
unselectable="on"
to it.

Use the onMouseDown event

Alternatively you can also use the onMouseDown event rather than the onClick event. This way the selection won't be lost yet when your JavaScript code does it's thing. But this on of course does slightly change the behaviour, and thus I prefer the first method.

07 July 2011

.NET - Foreach loop through a Dictionary

Looping a Dictionary<key, value> list using C#.NET is easy enough.
You just need to know how, and this is how:
private Dictionary<int, Customer> DataSupport { get; set; }

foreach (KeyValuePair<int, Customer> customer in DataSupport) {
  int key = customer.Key;
  Customer value = customer.Value;
}

.NET - Read/write a file line by line

To read some file line by line using C#.NET, I used this function:
if (File.Exists(App.CUSTOMERS_FILE_NAME)) {
  using (var reader = new StreamReader(App.CUSTOMERS_FILE_NAME)) {
    string line = string.Empty;
    while ((line = reader.ReadLine()) != null) {
      //Process the line
    }
  }
}

writing such a file is just as easy:
using (var writer = new StreamWriter(App.CUSTOMERS_FILE_NAME, false, Encoding.Unicode)) {
  writer.WriteLine("Whatever value");
}
The file will be automatically created if it doesn't exist yet.

04 July 2011

.NET Entity Framework - The version of SQL Server in use does not support datatype ‘datetime2′

I developed an application using the .NET Entity Framework and SQL Server 2008 on my local machine. When I moved it onto the production server, which runs SQL Server 2005, it threw this error as inner exception when trying to save a DateTime:
The version of SQL Server in use does not support datatype ‘datetime2′.
The solution is changing a setting in the Entity Framework to target SQL Server 2005 instead of 2008. This setting is not available through the IDE, so:
  1. Open the *.edmx,
  2. Find the ProviderManifestToken attribute on the Schema tag,
  3. Change it's value from 2008 to 2005,
  4. A rebuild might be necessary. 

30 June 2011

Javascript and IE - Get the selection start and end

In Opera and other browsers it is fairly easy to get the start and end positions of the selection in a textarea. Exept, of course, in Internet Explorer, where you need these:

Get the start and end

function synGetCaret(editor) {
  if(document.selection){
    editor.focus();
    var range = document.selection.createRange();
    var range2 = range.duplicate();
    range2.moveToElementText(editor);
    range2.setEndPoint('EndToEnd', range);
    var selStart = range2.text.length - range.text.length;
    return new Array(selStart, selStart + range.text.length);
  }
}
The return value is an array with 0 = start and 1 = end.

Set the selection

As opposed to Opera and other browsers, IE also looses the selection in a textarea when that textarea looses the focus. Therefore you feed the array that was retrieved above in this function to restore the selection:

function synSetCaret(editor, selection) {
  if (document.selection) {
    if (selection[0] == NaN) selection[0] = 0;
    if (selection[1] == NaN) selection[1] = selection[0];
    if (editor.setSelectionRange) {
      editor.setSelectionRange(selection[0], selection[1]);
    }
    else if (editor.createTextRange) {
      var range = editor.createTextRange();
      range.collapse(true);
      range.moveEnd('character', selection[1]);
      range.moveStart('character', selection[0]);
      range.select();
    }
  }
}

09 June 2011

WPF - Store the position of a GridSplitter

Storing and restoring the position of a GridSplitter element in WPF is rather easy.
Hereby an example on a horizonal splitter:

The layout

<Grid.RowDefinitions>
  <Rowdefinition Height="32">
  <Rowdefinition Height="7*" x:Name="rowDefTables">
  <Rowdefinition Height="3*">
</Grid.RowDefinition>

Store the position

This line would run when the program closes.
Note that rowdefTables is the name of the RowDefinition.
The GridSplitter itself does not even need a name!
mSettings.SplitterTablesColumnsPosition =
          Convert.ToInt32(rowdefTables.Height.Value);
mSettings.SaveSettings(); //To a .ini file

Restore the position

This is done when the program starts:
mSettings.LoadSettings(); //From the .ini file
if (mSettings.SplitterTablesColumnsPosition > 0)
  rowdefTables.Height = new GridLength(
                        (double)mSettings.SplitterTablesColumnsPosition,
                        GridUnitType.Pixel);

ASP.NET MVC - Store uploaded files

Here's how you can store uploaded files in ASP.NET MVC.
To work, the HTML file input control must be - and this is specific to HTML, not MVC - in a form that has it's enctype set to multipart/form-data.

public static void Store(HttpFileCollectionBase files,
                         EntityCollection list) {
  List attachments = new List();
  Attachment attachment = null;
  HttpPostedFileBase file = null;
  FileStream stream = null;
  string fullName = string.Empty;
  byte[] buffer = null;
  int length = 0;

  if (files != null && files.Count > 0) {
    foreach (string inputName in files) {
      if (!string.IsNullOrEmpty(inputName)) {
        file = files[inputName] as HttpPostedFileBase;
        if (file != null && !string.IsNullOrEmpty(file.FileName)) {
          //Generate file name
          fullName = Guid.NewGuid().ToString() + '-' + file.FileName;

          //Store the actual file
          using (stream = File.Create(
                 HttpContext.Current.Server.MapPath(
                 App.FOLDER_ATTACHMENTS + '/' + fullName))) {
            buffer = new byte[file.ContentLength];
            length = file.InputStream.Read(buffer, 0, file.ContentLength);
            stream.Write(buffer, 0, length);
          }

          //Create and attach to the entities
          attachment = new Attachment() {
            Name = fullName,
            Size = file.ContentLength
          };
          list.Add(attachment);
        }
      }
    }
  }
}

The files parameter above gets (HttpRequestBase)request.Files passed.
The function above will also associate the files with an entity, but that's another story.

26 May 2011

C# - Format a file size

Here's how you can format a file size, specified in bytes, into a nice string for display:
public const string DECIMAL_FORMAT = "0.##";
public static string ToFormattedSize(int size) {
  float KB = 1024f;
  float MB = 1024f * KB;
  float GB = 1024f * MB;

  if (!size.HasValue)
    return "-";
  else if ((float)size.Value > GB)
    return ((float)size.Value / GB).ToString(DECIMAL_FORMAT) + " GB";
  else if ((float)size.Value > MB)
    return ((float)size.Value / MB).ToString(DECIMAL_FORMAT) + " MB";
  else if ((float)size.Value > KB)
    return ((float)size.Value / KB).ToString(DECIMAL_FORMAT) + " KB";
  else
    return ((float)size).Value.ToString(DECIMAL_FORMAT) + " B";
}

17 May 2011

C# - Encryption/decryption

I wrote these extensions to easily encrypt strings and later decrypt them again.

Keys

First the encryption will need these.
For each project I use them in, I change the keys a little.
private static readonly byte[] KEY = { 15, 85, 64, 52, 131, 86, 216, 44 };
private static readonly byte[] IV = { 5, 44, 19, 95, 129, 164, 9, 108 };

Encrypt

public static string Encrypt(this string source) {
  try {
    if (string.IsNullOrEmpty(source))
      return source;
    else {
      using (var des = new DESCryptoServiceProvider())
      using (var ms = new MemoryStream())
      using (var cs = new CryptoStream(ms, des.CreateEncryptor(KEY, IV), CryptoStreamMode.Write))
      using (var sw = new StreamWriter(cs))
      {
          sw.Write(source);
          sw.Flush();
          cs.FlushFinalBlock();
          sw.Flush();
          return Convert.ToBase64String(ms.GetBuffer(), 0, (int)ms.Length);
      }
    }
  }
  catch {
    return string.Empty;
  }
}

Decrypt

public static string Decrypt(this string source) {
  try {
    if (string.IsNullOrEmpty(source))
      return source;
    else {
      using (var des = new DESCryptoServiceProvider())
      using (var ms = new MemoryStream(Convert.FromBase64String(source)))
      using (var cs = new CryptoStream(ms, des.CreateDecryptor(KEY, IV), CryptoStreamMode.Read))
      using (var sr = new StreamReader(cs))
      {
          return sr.ReadToEnd();
      }
    }
  }
  catch {
    return string.Empty;
  }
}

09 May 2011

C# - Parse JSON

Parsing JSON to strongly types objects is real easy in C#.
You just need to have the objects as they are represented in JSON, like these:

public class GridFilter {
  public string GroupOp { get; set; }
  public IEnumerable Rules { get; set; }
}

public class GridFilterRule {
  public string Field { get; set; }
  public string Op { get; set; }
  public string Data { get; set; }
}

Then all you need to do is this:

GridFilter filter = new JavaScriptSerializer().Deserialize(filters);

And your object structure will be created and filled from a JSON string.

Opera - High contrast on certain tabs

This is how in the Opera web browser you can have high contrast on some tabs and normal contrast on others. This is usefull - for me at least - to have white text on black on very light websites while still viewing other sites as normal.

To do this, you need the Appearance > Buttons > Browser view > User Mode button on the toolbar. Then:
  • Click the arrow next to this button and choose Manage Modes...,
  • Give both modes the same settings, but uncheck My style sheet for one of them,
  • In the mode that has the My style sheet setting, you can set the High Contrast option, in the other one you can't; so on a page in this mode set this option.
Now you can easily toggle between normal and high contrast by switching between author and user mode. This mode can be set per tab, so this way you can have normal and high contrast tabs in the same browser window.

05 May 2011

C# - Bitwise flags (bitmask)

Bitwise flags allow you to combine multiple flags into a single integer.
This really applies to many programming languages.
In C# you can do it like this:

The flags

The following defines the flags.
Notice how the value doubles - are powers of two - for each flag (binary system).
The flags attribute  indicates that bitwise operators will be performed on this enum.
[Flags]
public enum Role{
  AuxCreator = 1,
  AuxEditor  = 2,
  AuxDeletor = 4
}

Combine them

Getting the integer that combines some flags is easy using the bitwise or operator:
int roles = Role.AuxCreator | Role.AuxDeletor; //roles = 5

Check for flag set

Then, you can check whether a certain flag is set in the integer using the bitwise and operator as follows:
bool isAuxDeletor = (roles & Role.AuxDeletor) == Role.AuxDeletor; //isAuxDeletor = true

Unset a flag

To unset a flag from the bitmask, you can use the bitwise and operator again, with the inverse of the flag:
int roles = Role.AuxCreator & (~Role.AuxDeletor); //roles = 1

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.

    30 March 2011

    Silverlight - Isolated Storage

    When using Silverlight Isolated Storage, you have two options:

    Application or site

    Application
    Storage specific to the application and the user using it.
    Site
    Storage shared between all applications in a domain for the user.

    Read from IS

    using System.IO.IsolatedStorage;
    using(IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForSite()){
      if (storage.FileExists(IS_FILE_NAME)) {
        using(IsolatedStorageFileStream stream = new IsolatedStorageFileStream(IS_FILE_NAME, FileMode.Open, storage)){
          //Read the stream
        }
      }
    }
    

    Write to IS

    using(IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForSite()){
      using(IsolatedStorageFileStream stream = new IsolatedStorageFileStream(IS_FILE_NAME, FileMode.OpenOrCreate, storage)){
        stream.WriteLine("EGS rules!");
      }
    }
    

    28 March 2011

    XAML - Value converter

    In XAML, you can use value converters to convert a bound business data value into a GUI-usable value using a class like this one:

    public class CurrencyConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) =>
            ((double)value).ToString("C");
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) =>
            double.Parse((string)value);
    }
    

    A converter must be put in the resources like so:

    <this:CurrencyConverter x:Key="CurrencyConverter" />
    

    You can put it in App.xaml for project-wide usage.

    To be then included in a binding like this.
    You can also pass it a parameter if you like:

    {Binding Amount, Converter={StaticResource CurrencyConverter}}
    {Binding Amount, Converter={StaticResource CurrencyConverter}, ConverterParameter=EUR}
    

    The parameter is passed as a string.
    If you want to pass something else, you can use a markup extension.

    25 March 2011

    .NET | WPF - Localization

    The following describes how I localized a WPF application:

    I created a folder and put .NET .resx files in it. The default language was called Lan.resx; the localized one was called Lan.nl-BE.resx.

    Then I added a class called Culture, containing a function called GetCulture() that returns a new Resources.Lan(), and a function called Set(CultureInfo culture) that sets the culture of the current thread by doing Thread.CurrentThread.Current(UI)Culture = culture.

    In the App.xaml I added an application resource as follows:
    <ObjectDataProvider x:Key="Lan" ObjectType="{x:Type this:Culture}" MethodName="GetCulture" />

    To change the culture I can then do:
    Culture.Set(culture);
    ((ObjectDataProvider)App.Current.FindResource("Lan")).Refresh();
    

    Finally, controls are localized using statements like this:
    {Binding Path=Options, Source={StaticResource Lan}}
    

    23 March 2011

    ASP.NET - Give trust to an assembly

    One day SharePoint gave me the exception "Request for the permission of type 'System.Data.Odbc.OdbcPermission...". The sites trust level set in Web.config was:
    <trust level="WSS_Minimal" originUrl="" />

    Thus I had to edit the WSS_Minimal, the location of which is also indicated in the Web.config. In my case: 14\config\wss_minimaltrust.config.

    In this file I added the following line to the SecurityClasses:
    <SecurityClass Name="OdbcPermission" Description="System.Data.Odbc.OdbcPermission, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>

    And this one under PermissionSet:
    <IPermission class="OdbcPermission" version="1" Unrestricted="true" />

    And I was back in business.

    22 March 2011

    SharePoint - Enable SessionState in SharePoint 2010

    I had SharePoint 2010 giving me an exception telling me to enable SessionState, so here's how I did that:
    • Run the SharePoint 2010 Management Shell located in the Start menu as administrator,
    • In it, run the command "enable-SPSessionStateService",
    • Give this command some database name,
    • In the Web.config, set enableSessionState to true.

    21 March 2011

    SharePoint - Import a list from 2007 into 2010

    I had myself a bit of a problem when trying to bring a SharePoint 2007 list with data to SharePoint 2010. I exported the lists as .iqy files and created new lists in 2010 using the Import Spreadsheet option. Of my 4 lists, 3 had the wrong column as their title field, and I couldn't get it right.

    So I thought I'd try getting the list across via a list template .stp file. So done, my list template did show up in the Create window, but an error followed, stating:
    Microsoft SharePoint Foundation version 3 templates are not supported in this version of the product

    That's when I sought and found this solution:
    • Go to List Settings and choose Save list as template,
    • Rename the .stp file as a .cab file,
    • Extract the manifest.xml file in the .cab file,
    • In that file, set ProductVersion from 3 to 4,
    • Open a command prompt in C:\Windows\System32,
    • Run the command makecab ...\manifest.xml ...\ListName.cab,
    • Rename the .cab back to a .stp,
    • Import this template in SharePoint 2010, under Site Settings > List templates,
    • Create a list from the template, and all will be good!

    08 March 2011

    Internet Explorer - Open pop-ups as tabs

    To get IE (7, 8, ...) to always open pop-ups in tabs, and not new windows, do as follows:
    1. Click Tools > Internet Options,
    2. On the tab General, under Tabs, click Settings,
    3. Under When a pop-up is encountered, select Always open pop-ups in a new tab, and click OK.
    This was usefull for me when working with Microsoft CRM 2011 online.

    04 March 2011

    CRM - Silverlight web resource in host

    To display a Silverlight control in a HTML host page in CRM (2011 online), you do this:
    1. Create a new web resource of type Silverlight and upload it,
    2. In the host page, change the source parameter to the Name you gave the Silverlight control in CRM; e.g. "syn_customers_per_company",
    3. Create a new web resource of type ''Web page'' and upload the host page.

    02 March 2011

    Silverlight - Preventing the build of localized dll's

    When you build a Silverlight (4) project, the Bin folder get filled up with localized versions of the dll's referenced in the projects where these localized versions exist.
    It turns out they are found here:
    C:\Program Files (x86)\Microsoft SDKs\Silverlight\v4.0\Libraries\Client
    I suppose it's a nice feature in some cases, but it rather annoyed me, so I wanted to get rid of them. So I deleted all the localized sub folders in the SDK (de, fr, za-Hans, etc.) and yes!, at the next build localized dll's were no longer generated.

    Silverlight - Dynamic service client and init params

    Before, when I connected my Silverlight application to a web service, the web services URI was static. To make this dynamic I referenced System.ServiceModel, and implemented this class:
    using System;
    using System.ServiceModel;
    using System.ServiceModel.Channels;
    using System.Windows;
    using EGS.KeyGen.QueryService;
    
    namespace EGS.KeyGen {
      internal class DynamicServiceClient {
        internal static QueryServiceSoapClient GetClient() {
          BasicHttpSecurityMode securityMode = Application.Current.Host.Source.Scheme.Equals("https") ? BasicHttpSecurityMode.Transport : BasicHttpSecurityMode.None;
          BasicHttpBinding binding = new BasicHttpBinding(securityMode);
          binding.MaxReceivedMessageSize = int.MaxValue;
          binding.MaxBufferSize = int.MaxValue;
          return new QueryServiceSoapClient(binding, new EndpointAddress(new Uri(App.ServiceUrl)));
        }
      }
    }
    

    When a function wants to retrieve data, it no longer creates a SOAP client itself, but asks one from this class. The dynamic URI is a static property I defined in the App class that takes it's value from the init params on the Silverlight host page:
    <param name="initParams" value="ServiceUrl=http://www.EGS.be/QueryService.asmx" />
    
    and sets it like so:
    private void Application_Startup(object sender, StartupEventArgs e) {
      if (e.InitParams.ContainsKey("ServiceUrl"))
        ServiceUrl = e.InitParams["ServiceUrl"];
    ...
    

    And this way I can change the web service end point without having to rebuild the Silverlight application, even though the application still has a static end point from when the service reference was created.

    24 February 2011

    HTML - Trigger button on enter key

    The following will cause a buttons click event to fire when pressing [Enter] in a text box:
    <input type="text" onkeypress="if(event.keyCode==13) document.getElementById('btnToTrigger').click()" />
    

    23 February 2011

    .NET - String to hexadecimal and vice versa

    The following functions encode a string to hexadecimal form and the other way round. I use this method to avoid encoding issues in data files:
    protected string EncodeStrToHex(string str) {
      if (string.IsNullOrEmpty(str))
        return str;
      byte[] chars = Encoding.UTF8.GetBytes(str);
      StringBuilder result = new StringBuilder(chars.Length);
      foreach (byte c in chars) {
        result.Append(c.ToString("X2"));
      }
      return result.ToString();
    }
    
    protected string EncodeHexToStr(string hex) {
      if (string.IsNullOrEmpty(hex))
        return hex;
      byte[] chars = new byte[hex.Length / 2];
      string c = string.Empty;
      for (int i = 0, j = 0; i < chars.Length; i++, j += 2) {
        c = new string(new char[] { hex[j], hex[j + 1] });
        chars[i] = byte.Parse(c, NumberStyles.HexNumber);
      }
      return Encoding.UTF8.GetString(chars);
    }
    

    ASP.NET - ValidateRequest and .NET Framework 4

    When building a website in ASP.NET using the .NET Framework 4, ValidateRequest doesn't work as it used to anymore.

    The solution lies in the Web.config, where you add:
    <httpRuntime requestValidationMode="2.0" />
    to the
    <system.web>
    section.

    08 February 2011

    .NET - Generic casting to nullable types

    The following is part of a function that reads a value from an XML node and casts it to a given type. The function uses:

    Convert.ChangeType(value, type)

    to do the casting, but this doesn't work for nullable types.
    To solve this problem, the following section was added:

    else if (type.IsGenericType &&
             type.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) {
      if (string.IsNullOrEmpty(value)) {
        return defaultValue; //Commonly 'null'
      }
      else {
        NullableConverter nullConv = new NullableConverter(type);
        return Convert.ChangeType(value, nullConv.UnderlyingType);
      }
    }
    

    The result of this function, which returns an object, is casted to the desired - nullable - type on the line where it is called.

    02 February 2011

    CRM - Register and use a plugin

    To register and use a plugin in CRM (2011 online), you best use the Plugin Registration Tool provided in the CRM SDK:
    • I not yet: download and install Windows Identity Foundation,
    • Build the Plugin Registration Tool source code.

    Register the plugin via the tool:
    • Add a connection to the CRM server,
    • Register > Register New Assembly, and select which plugins,
    • Choose 'Sandbox' and 'Database', and click 'Register'.

    To use the plugin via the tool:
    • Register > Register New Step
    • 'Message': the event on which to run,
    • 'Primary Entity': the entity on which that event occurs,
    • Select when to run relative to the event itself,
    • Click 'Register New Step'.

    01 February 2011

    .NET/SQL - Split multiple statements

    For the project 'DatabaseTool', I had to split a query that could contain multiple statements into those multiple statements. For this I required each statement to end with a ';' and start on a new line. I wrote the following function to split them:

    public IEnumerable GetStatements(string query) {
      string[] parts = query.Split(new string[] { ";\r\n" },
                                   StringSplitOptions.RemoveEmptyEntries);
      return from p in parts
             select p.Trim(new char[] { ' ', ';', '\t' });
    }
    

    I didn't split on white lines because those can also occur within statements; and it's to risky when UPDATE's and WHERE's are involved.

    27 January 2011

    .NET - Using the clipboard

    I used following code to insert text at cursor position in a textbox from a context menu on a ListBox:

    Clipboard.SetData(DataFormats.Text, text);

    txtQuery.Paste();

    26 January 2011

    Silverlight - Child window

    In Silverlight, you can create a child window using Add > New Item > Silverlight Child Window. Such window creates a class and doesn't need to be embedded in the XAML from which you want to open it. You open it in code with a simple:

    new frmLeadEdit().Show();

    The window overlays the entire Silverlight area and blocks underlaying controls. I customized it's style. Make sure the styles TargetType has the proper prefix. I had a browser crash without it.

    The window can return a 'DialogResult' of True or False. To receive it, you must handle the windows 'Closed' event.

    19 January 2011

    XAML - Scaling UI elements with fixed width and height

    Sometimes you want the size of a XAML UI element to be dynamic and set it's width and height at the same time. This can be done by:
    • Adding the following using:

      xmlns:toolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit"

    • Wrapping the UI element in following tag:

      <toolkit:Viewbox Stretch="Uniform">

      </toolkit:Viewbox>

    14 January 2011

    .NET - Custom event

    Sometimes you need to throw your own custom event with custom arguments. The arguments can be passed directly or by implementing a custom class that inherits from EventArgs. The latter is needed when adding handlers on the event in for instance XAML. The event can be e.g.:

    public delegate void ValidationEventHandler(object sender, ValidationEventArgs e);
    public event ValidationEventHandler Validation;
    protected virtual void OnValidation(string propertyName, bool isValid, string message) {
      if (Validation != null)
        Validation(this, new ValidationEventArgs(propertyName, isValid, message));
    }
    

    Which can then be raised by:

    OnValidation("Code", false, "Value must not be empty.");
    

    Or you skip the helper method. Make sure the event is not null, meaning there are no listeners:

    Validation?.Invoke(this, new ValidationEventArgs(nameof(Code), false, "Value must not be empty."));
    

    You can also use the generic delegate. It can be invoked the same way.

    public event EventHandler<ValidationEventArgs> Validation;
    

    .NET - Implementing INotifyPropertyChanged

    To implement the INotifyPropertyChanged interface on a business object:
    • Implement the interface System.ComponentModel.INotifyPropertyChanged,
    • Add a method like this:
      private void NotifyPropertyChanged([CallerMemberName]string propertyName = null) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
      
    • Use this method in every setter that must notify:
      NotifyPropertyChanged();

    .NET - Decorate object properties for data binding

    If you set the AutoCreateColumns property of a DataGridView to True, all public properties of a bound object type will appear as columns. However, you can manipulate how they appear by decorating these properties.

    Using [Browsable(false)], the property will not be added as a column.

    Using [DisplayName("The header text")], you set the column header text for the property.

    07 January 2011

    SharePoint - Install custom web service

    To install a custom web service in SharePoint (2007):
    • Create a web service assembly and build it,
    • Set it's 5-part strong name as class attribute in the asmx file (right-click > View Markup),
    • Install the signed assembly in the GAC,
    • Put the asmx in the 12\TEMPLATE\LAYOUTS folder,
    • Copy disco.exe (the tool) to the same location,
    • Run a command prompt and cd to that location,
    • Run the command disco http://<server>/_layouts/<service>.asmx,
    • Include the 2 generated files *.disco and *.wsdl in the web service project,
    • Remove the '.' preceding their extensions and append ".aspx" to their names,
    • In the *disco.aspx file, replace everything by the following. Don't change anything to the headers, not even put them on new lines, as SharePoint won't find the file anymore. The same goes for the WSDL that comes next.
      <%@ Page Language="C#" Inherits="System.Web.UI.Page" %> <%@ Assembly Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Import Namespace="Microsoft.SharePoint.Utilities" %> <%@ Import Namespace="Microsoft.SharePoint" %>
      <% Response.ContentType = "text/xml"; %>
      <discovery xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/disco/">
      <contractRef ref=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(SPWeb.OriginalBaseUrl(Request) + "?wsdl"),Response.Output); %> docRef="http://www.syneton.be/_layouts/SynetonService.asmx" xmlns="http://schemas.xmlsoap.org/disco/scl/" />
      <soap address=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(SPWeb.OriginalBaseUrl(Request)),Response.Output); %> xmlns:q1="http://www.syneton.be/services/" binding="q1:SynetonServiceSoap" xmlns="http://schemas.xmlsoap.org/disco/soap/" />
      <soap address=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(SPWeb.OriginalBaseUrl(Request)),Response.Output); %> xmlns:q2="http://www.syneton.be/services/" binding="q2:SynetonServiceSoap12" xmlns="http://schemas.xmlsoap.org/disco/soap/" />
      </discovery>
    • In the *wsdl.aspx file, add the following to the top of the file:
      <%@ Page Language="C#" Inherits="System.Web.UI.Page" %> <%@ Assembly Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Import Namespace="Microsoft.SharePoint.Utilities" %> <%@ Import Namespace="Microsoft.SharePoint" %>
      <% Response.ContentType = "text/xml"; %>

      And at the bottom, replace the location attribute of <soap:address... and <soap12:address... both as follows:
      location=<% SPHttpUtility.AddQuote(SPHttpUtility.HtmlEncode(SPWeb.OriginalBaseUrl(Request)),Response.Output); %>
    • Now put those 2 files and the asmx under 12\ISAPI and it's done.
    • The service is now available from http://<server>/_vti_bin/<service>.asmx.

      PHP - Starts|ends with

      Two convient general purpose functions from .NET for PHP:

      function startsWith($Text, $Value){
        return strpos($Text, $Value) === 0;
      }
      
      function endsWith($Text, $Value){
        return strrpos($Text, $Value) === strlen($Text) - strlen($Value);
      }
      

      06 January 2011

      SharePoint - Deploy custom field

      In SharePoint (2007), custom fields — custom column types you can add to lists — are deployed through 3 steps:
      • Install the signed assembly in the GAC,
      • Deploy the fldtypes*.xml to \12\TEMPLATE\XML,
      • Deploy the *.ascx without it's .cs to \12\TEMPLATE\CONTROLTEMPLATES.
      After an IISRESET the thing should then work.

      Notes on custom fields, e.g. for the error Type X not found:
      • Make sure the DefaultTemplateName matches the ID of the RenderingTemplate.

      05 January 2011

      XAML - Custom button style

      An example style for a custom button to put in a resource dictionary:

      Silverlight

      <Style TargetType="Button">
        <Setter Property="Cursor" Value="Hand" />
        <Setter Property="Margin" Value="2" />
        <Setter Property="Template">
          <Setter.Value>
            <ControlTemplate TargetType="Button">
              <Grid>
                <VisualStateManager.VisualStateGroups>
                  <VisualStateGroup Name="Common">
                    <VisualState Name="Normal">
                      <Storyboard>
                        <ColorAnimation Storyboard.TargetName="objBackgroundTop" Storyboard.TargetProperty="Color" Duration="0:0:0.2" From="Green" To="#EEEEEE" />
                      </Storyboard>
                    </VisualState>
                    <VisualState Name="MouseOver">
                      <Storyboard>
                        <ColorAnimation Storyboard.TargetName="objBackgroundTop" Storyboard.TargetProperty="Color" Duration="0:0:0.2" From="#EEEEEE" To="Green" />
                      </Storyboard>
                    </VisualState>
                    <VisualState Name="Pressed">
                      <Storyboard>
                        <ColorAnimation Storyboard.TargetName="objBackgroundTop" Storyboard.TargetProperty="Color" Duration="0:0:0.2" From="Green" To="CornflowerBlue" />
                      </Storyboard>
                    </VisualState>
                    <VisualState Name="Disabled">
                      <Storyboard>
                        <ColorAnimation Storyboard.TargetName="objBackgroundTop" Storyboard.TargetProperty="Color" Duration="0:0:0.2" From="#EEEEEE" To="#444444" />
                      </Storyboard>
                    </VisualState>
                  </VisualStateGroup>
                </VisualStateManager.VisualStateGroups>
                <Rectangle RadiusX="5" RadiusY="5">
                  <Rectangle.Fill>
                    <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                      <GradientStop Offset="0" Color="#EEEEEE" x:Name="objBackgroundTop" />
                      <GradientStop Offset="1" Color="#111111" />
                    </LinearGradientBrush>
                  </Rectangle.Fill>
                </Rectangle>
                <ContentPresenter />
              </Grid>
            </ControlTemplate>
          </Setter.Value>
        </Setter>
      </Style>

      WPF

      Another example for WPF. Here I used triggers and resources:

      <Style x:Key="Button" TargetType="Button">

        <Style.Resources>

          <LinearGradientBrush x:Key="lgbNormal" StartPoint="0,0" EndPoint="0,1">

            <GradientStop Offset="0" Color="{x:Static SystemColors.ControlLightLightColor}" />

            <GradientStop Offset="0.5" Color="{x:Static SystemColors.ControlLightColor}" />

            <GradientStop Offset="0.5" Color="{x:Static SystemColors.ControlDarkDarkColor}" />

            <GradientStop Offset="1" Color="{x:Static SystemColors.ControlDarkDarkColor}" />

          </LinearGradientBrush>

          <LinearGradientBrush x:Key="lgbMouseOver" StartPoint="0,0" EndPoint="0,1">

            <GradientStop Offset="0" Color="{x:Static SystemColors.ControlLightLightColor}" />

            <GradientStop Offset="0.5" Color="#083B80" />

            <GradientStop Offset="0.5" Color="{x:Static SystemColors.ControlDarkDarkColor}" />

            <GradientStop Offset="1" Color="{x:Static SystemColors.ControlDarkDarkColor}" />

          </LinearGradientBrush>

        </Style.Resources>

        <Setter Property="Template">

          <Setter.Value>

            <ControlTemplate TargetType="Button">

              <Border x:Name="border" BorderThickness="1" BorderBrush="#3E3E3E" CornerRadius="2">

                <Grid>

                  <Rectangle x:Name="rect" RadiusX="2" RadiusY="2" Fill="{StaticResource lgbNormal}" />

                  <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />

                </Grid>

              </Border>

              <ControlTemplate.Triggers>

                <Trigger Property="IsMouseOver" Value="True">

                  <Setter TargetName="rect" Property="Fill" Value="{StaticResource lgbMouseOver}" />

                  <Setter TargetName="border" Property="BorderBrush" Value="#083B80" />

                </Trigger>

                <Trigger Property="IsEnabled" Value="False">

                  <Setter TargetName="border" Property="Opacity" Value="0.5" />

                </Trigger>

              </ControlTemplate.Triggers>

            </ControlTemplate>

          </Setter.Value>

        </Setter>

      </Style>

      XAML - Convert SVG to XAML and use as a resource on a button

      I wanted to use some nice icons in SVG format in Silverlight.
      Silverlight doesn't support SVG though.
      So I found a tool that can convert them to XAML.
      It's a command line tool that can be used as follows:

      svg2xaml D:\Projects\ArrowUp.svg

      To make it valid I had to tweak the result a bit.
      One thing was to remove the PathGeometry's and put their data directly in the Path's.
      Then I surrounded it with:

      <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                         xmlns:toolkit="clr-namespace:System.Windows.Controls;
                                        assembly=System.Windows.Controls.Toolkit">
        <Style x:Key="ArrowUp" TargetType="Button">
          <Setter Property="Template">
            <Setter.Value>
              <ControlTemplate TargetType="Button">
                <toolkit:Viewbox Stretch="Uniform">
                  <!-- The XAML -->
                </toolkit:Viewbox>
              </ControlTemplate>
            </Setter.Value>
          </Setter>
        </Style>
      </ResourceDictionary>

      put it's build action to "Content" and included it with:

      <this:frmBase.Resources>
        <ResourceDictionary>
          <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="Images/ArrowDown.xaml" />
          </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
      </this:frmBase.Resources>

      Then I used the resource as follows:

      <Button Style="{StaticResource MenuButton}">
        <Button.Content>
          <Button Style="{StaticResource ArrowDown}" Click="Button_Click" />
        </Button.Content>
      </Button>

      where "MenuButton" is another global style resource with a custom template containing a ContentPresenter.