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.