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.