Follow @PDSAInc Paul Sheriff's Blog for the Real World

Paul Sheriff's Blog for the Real World

This blog is to share my tips and tricks garnered over 20+ years in the IT industry

Paul's Favorites

Client-Side Logging in Silverlight

Many of us have implemented logging in our ASP.NET, Windows Forms and WPF applications, so why shouldn’t you do the same in your Silverlight applications? Well, you should. In this blog post I will show you one approach on how you might perform this logging. The class I will use is called PDSALoggingManager. This class has a method named Log() you use to publish data into a log file in your Silverlight application. A method named LogException() is also available for logging information about any exceptions that happen on the client-side of your Silverlight application. Let’s take a look at the usage of the PDSALoggingManager class.

Logging Data

The simplest way to log information using the PDSALoggingManager class is to call the Log() method with some string data as shown  below:

PDSALoggingManager.Instance.Log("Some data to log");

This will add the string passed to the Log() method to an internal StringBuilder object that contains the log information followed by a NewLine character. The Log() method also writes the string to a file located in isolated storage. What is written for each piece of data passed to the Log() method is shown here:

'Informational' log entry written on 5/22/2012 5:51:48 AM, from class: 'SL_Log.MainPage'
   Some Data To Log

If you set the LogSystemInfo property on the PDSALoggingManager class prior to calling Log(), then system information is written to the log at the same time as the log data. Below is a sample of the log data with the system information appended to the end.

---------------------------------------------------------
'Informational' log entry written on 5/22/2012 5:51:48 AM, from class: 'SL_Log.MainPage'
   Some Data To Log
System Information
   DateTime=5/22/2012 5:51:48 AM
   Current URL=file:///D:/MyStuff/BlogEntries/2012/
     Samples/SL-Log/SL-Log/Bin/Debug/SL_LogTestPage.html
   OSVersion=Microsoft Windows NT 6.1.7601 Service Pack 1
   OSName=Windows 7
   CurrentAssemblyName=PDSA.Silverlight, Version=5.0.0.0,
       Culture=neutral, PublicKeyToken=null
   MainAssemblyName=SL-Log, Version=1.0.0.0, Culture=neutral,
       PublicKeyToken=null
   AppDomainName=Silverlight AppDomain
   UserLanguage=en-US
   CompanyName=PDSA, Inc.
   ProductName=Silverlight Logging
   Description=Silverlight Logging
   Title=Silverlight Logging
   Copyright=Copyright © 2012 by PDSA, Inc.
   ApplicationVersion=1.0.0.0
   Stack Trace={LogInfoSample,btnLogInfo_Click}
-----------------------------------------------------------

The system information added to the end of the log comes from another class called PDSASystemInfo. Note that I blogged about this class earlier, so check out my previous blog entry at http://weblogs.asp.net/psheriff/archive/2012/05/20/retrieve-system-information-in-silverlight.aspx for information on this class and how that data was gathered.

Passing Extra Data to Log

You have an additional overload on the Log() method that takes a generic Dictionary<string, string> object you load with key/value pairs of data. Call this version of Log() like the following:

Dictionary<string, string> extra =
   new Dictionary<string, string>();

extra.Add("CustomerId", "1");
extra.Add("StateCode", "CA");

PDSALoggingManager.Instance.Log("Some data to log", extra);

Passing a key/value pair passed into the Log() method you can add any amount of extra data you want to your log very simply. When this log entry is written, you end up with an entry that looks like the following:

'Informational' log entry written on 5/22/2012 5:53:47 AM, from class: 'SL_Log.MainPage'
   Some data to log
Extra Values Passed In From Application
   CustomerId=1
   StateCode=CA

The Log Method

Let’s now take a look at the Log() method in the PDSALoggingManager class. When you pass in a single string value, the following version of the Log() method is called.

public void Log(string value)
{
  this.Log(value, "Informational", null);
}

This method calls another overload of the Log() method to which you can pass in the “type” of log entry you are writing and a null in place of the Dictionary object. By default, the Log() method uses “Informational” as the log type. You can pass in whatever value you wish for this type.

The 2nd overload of this method is the one that you pass in the Dictionary object to. This method calls the same Log() method as the previous one, but this time passes the extra values from the Dictionary object.

public void Log(string value,
   Dictionary<string, string> extraValues)
{
  this.Log(value, "Informational", extraValues);
}

Now, let’s look at the version of the Log() method that does the actual work of logging the string data, the type and optionally the extra dictionary values you might pass in. The first thing Log() does is to call a method named GetCallingClassName(). This method will be shown later, but it is used to retrieve the name of the method in your Silverlight application that called the Log() method. Next, it calls a method named Format() that will format the log data into what you saw earlier in this blog. Finally, the entry is written to isolated storage.

public void Log(string value, string logType,
  Dictionary<string, string> extraValues)
{
  IsolatedStorageFile file = null;
  string message = string.Empty;

  try
  {
    // Get the name of the calling method
    CallingClassName = GetCallingClassName();
    // Format the log entry
    message = Format(value, logType, extraValues);

    file = IsolatedStorageFile.GetUserStoreForSite();
    using (IsolatedStorageFileStream fs = new
       IsolatedStorageFileStream(LogFileName,
         FileMode.Append, file))
    {
      using (StreamWriter sw = new StreamWriter(fs))
      {
        sw.WriteLine(message);
      }
    }
  }
  catch (Exception ex)
  {
    TheLog.Append("Exception Occurred in Log() method" +
      Delimiter + ex.ToString());
  }
  finally
  {
    if (file != null)
      file.Dispose();
  }
}

Format Method

The Format() method is used to put the log entry into a readable format. A StringBuilder object, named sb, is what is used to format the data and concatenate all of the data together. Once all of the data is gathered up, this local StringBuilder object is appended to the ‘TheLog’ property. This property is kept in memory so you can retrieve the log during the running of your application without having to read the data from the isolated storage file. This property is also used to log any exception that occurs within the PDSALoggingManager class itself.

Notice there is another property called Delimiter that is used to separate each line of the log. This property is initialized in the constructor of the PDSAloggingManager class to Environment.NewLine.

protected virtual string Format(string value, string logType,
                Dictionary<string, string> extraValues)
{
  StringBuilder sb = new StringBuilder(512);

  if (string.IsNullOrEmpty(Delimiter))
    Delimiter = Environment.NewLine;

  if (LogSystemInfo)
    sb.Append(new string('-', 200) + Delimiter);

  sb.Append("'" + logType + "'");
  sb.Append(" log entry written on "
            + DateTime.Now.ToString());
  if (!string.IsNullOrEmpty(CallingClassName))
    sb.Append(", from class: '" + CallingClassName + "'");
  sb.Append(Delimiter);
  sb.Append("   " + value + Delimiter);
  // Add on Extra Values
  sb.Append(FormatKeyValuePairs(extraValues));
  if (LogSystemInfo)
  {
    PDSASystemInfo si = new PDSASystemInfo();

    sb.Append(si.GetAllSystemInfo(Delimiter));
    sb.Append(Delimiter);
    sb.Append(new string('-', 200) + Delimiter);
  }

  // Append to the main log property
  TheLog.Append(sb.ToString());

  return sb.ToString();
}

A property called LogSystemInfo is initialized to true in the constructor of this class. If set to true, then system information is gathered from the PDSASystemInfo class and appended to the log. If there are any extra values passed in the Dictionary object, those values are also appended to the log. These are formatted in the FormatKeyValuePairs() method. You can look up this method by downloading the code for this blog entry. See the end of this blog for instructions on how to get this article and the associated code sample.

GetCallingClassName Method

The PDSALoggingManager and PDSASystemInfo classes are located in a DLL named PDSA.Silverlight and is referenced from your Silverlight application. It is, of course, a best practice to put generic classes like this into a separate DLL. However, there is another benefit we derived from doing this. We want to retrieve the name of the method that called the Log() method so we can record where Log() was called from. The StackFrame object is used to retrieve each method in the stack trace. As we grab each method we can check the method to see if it is in the current assembly and if it is, we will ignore it. However, once we find a method that is in a different assembly, we can assume that this is the assembly and method that called the Log() method.

public string GetCallingClassName()
{
  int loop = 0;
  string ret = string.Empty;
  string currentName =
     Assembly.GetExecutingAssembly().FullName;

  try
  {
    StackFrame sf = new StackFrame(loop);
    while (sf.GetMethod() != null)
    {
      // Don't get any methods contained in this assembly.
      if (sf.GetMethod().DeclaringType.Assembly.FullName !=
          currentName)
      {
        ret = sf.GetMethod().DeclaringType.FullName;
        break;
      }

      loop++;
      sf = new System.Diagnostics.StackFrame(loop);
    }
  }
  catch
  {
    // Do nothing
  }

  return ret;
}

Logging Exceptions

In addition to logging string data, you might also wish to log exception data. To facilitate this I added a LogException() method. This method will accept an Exception object. By default, this method simply takes the result of the ToString() method on the exception object and passes it to the Log() method. However, you could modify this to retrieve any additional information from the Exception object that you want and pass that to the Log() method.

try
{
  decimal ret = 10;

  ret = ret / 0;
}
catch (Exception ex)
{
  PDSALoggingManager.Instance.LogException(ex);
}

A second overload of the LogException() method allows you to pass in additional information as a generic Dictionary object just like the original Log() method allows.

decimal ret = 10;

try
{
  ret = ret / 0;
}
catch (Exception ex)
{
  Dictionary<string, string> extra =
     new Dictionary<string, string>();

  extra.Add("StackTraceFromException", ex.StackTrace);
  extra.Add("ret variable", ret.ToString());

  PDSALoggingManager.Instance.LogException(ex, extra);
}

Here is the output from logging the exception:

'Exception' log entry written on 5/22/2012 4:10:15 PM,
  from class: 'SL_Log.MainPage'
   System.DivideByZeroException: Attempted to divide by zero.
   at System.Decimal.FCallDivide(Decimal& d1, Decimal& d2)
   at System.Decimal.op_Division(Decimal d1, Decimal d2)
   at SL_Log.MainPage.btnLogException_Click(Object sender,
     RoutedEventArgs e)

Getting the Log from your User

Once you have logged the data, you might want to get that information. The obvious choice would be to pass the complete log information to a WCF service. I am not presenting that choice in this sample due to space. However, one thing you need to consider is what if your user cannot access the WCF service for some reason? In this case you should have a backup plan. Two options you might consider are one, give the user a button they can click on that will copy the log to the clipboard, and two, another button that they can use to save the log data to a file on their computer. First, here is the code you would write to copy the log to the clipboard.

try
{
  Clipboard.SetText(PDSALoggingManager.Instance.ReadLog());
}
catch
{
  MessageBox.Show("Can't copy to the Clipboard.");
}

The ReadLog() method returns the data from the TheLog property, or if that is empty, will read the data from the isolated storage file. Next, you could read the log data and pass that to a method that will prompt the user to enter the name and location on their hard drive where to store the log data.

private void btnSaveToFile_Click(object sender,
 RoutedEventArgs e)
{
  SaveToFile(PDSALoggingManager.Instance.ReadLog());
}

private void SaveToFile(string contents)
{
  SaveFileDialog sfd = null;

  try
  {
    sfd = new SaveFileDialog();
    sfd.DefaultExt = "txt";
    sfd.Filter = "Log Files (*.log)|*.log|
                  All Files (*.*)|*.*";
    sfd.FilterIndex = 1;

    bool? result = sfd.ShowDialog();

    if (result.HasValue && result == true)
    {
      using (StreamWriter sw =
              new StreamWriter(sfd.OpenFile()))
      {
        sw.Write(contents);
        sw.Close();
      }
    }
  }
  catch (Exception ex)
  {
    MessageBox.Show(ex.Message);
  }
}

After storing this file on their hard drive, they could then attach that file to an email and send the log data to you.

Summary

Implementing a logging system in your Silverlight application is a great way to keep track of what you user does in your application. It is also extremely useful for tracking down errors. You must still be able to get the log file from the user, but that is fairly easy using either the clipboard or saving to a file and having your user email you the log. Hopefully this simple little class will give you a head-start on creating your own logging system.

NOTE: You can download the sample code for this article by visiting my website at http://www.pdsa.com/downloads. Select “Tips & Tricks”, then select “Client-Side Logging in Silverlight” from the drop down list.

 

Retrieve System Information in Silverlight

In a Silverlight application we are building for a client, they wanted an About screen that would display system information such as the current URL, the operating system name and version, the product name and various other information. In the same application, we built a logging system to gather this same information and write that information to a file to help developers troubleshoot issues. We decided to create a Silverlight class that would gather the information shown in Figure 1.

Figure 1: A Silverlight system information class to gather information about the user’s environment.

Figure 1: A Silverlight system information class to gather information about the user’s environment.

The class where all of this data comes from is named PDSASystemInfo. This class contains a set of properties that get information from the current executing assembly, the Environment class, and a few other classes that give you system information in your Silverlight application. Let’s look at each of these properties in turn.

The Constructor

First off, the constructor for this class retrieves the main assembly for your Silverlight application. This is the first assembly that runs. I assume that the first assembly is where your Silverlight user controls run from, so we need a reference to that assembly in order to retrieve copyright, title, company, and description information. You use the Application.Current.GetType() method to get the Assembly object. From this object you will be able to retrieve the Assembly information you place into your Silverlight application from Visual Studio. A reference to this assembly is placed into a private variable called _CurrentAssm.

public class PDSASystemInfo
{
  private Assembly _CurrentAssm = null;

  public PDSASystemInfo()
  {
    _CurrentAssm = Application.Current.GetType().Assembly;
  }

   …
   …
}

Assembly Information Properties

In Visual Studio if you go into the Project Properties of your solution you can click on the Assembly Information button and enter information about your assembly as shown in Figure 2.

Figure 2: The Visual Studio Assembly Information screen is where you enter information about your application.

Figure 2: The Visual Studio Assembly Information screen is where you enter information about your application.

To retrieve this information at runtime, you use the Application’s main assembly object to call the GetCustomAttributes() method. You pass to this method a type that represents the piece of information you wish to retrieve such as the Company, Product, etc.

public string Company
{
  get
  {
    Type at = typeof(AssemblyCompanyAttribute);
    object[] c = _CurrentAssm.GetCustomAttributes(at, false);
    AssemblyCompanyAttribute att =
      ((AssemblyCompanyAttribute)(c[0]));
    return att.Company;
  }
}

public string Description
{
  get
  {
    Type at = typeof(AssemblyDescriptionAttribute);
    object[] c = _CurrentAssm.GetCustomAttributes(at, false);
    AssemblyDescriptionAttribute att =
       ((AssemblyDescriptionAttribute)(c[0]));
    return att.Description;
  }
}

public string Product
{
  get
  {
    Type at = typeof(AssemblyProductAttribute);
    object[] c = _CurrentAssm.GetCustomAttributes(at, false);
    AssemblyProductAttribute att =
       ((AssemblyProductAttribute)(c[0]));
    return att.Product;
  }
}

public string Title
{
  get
  {
    Type at = typeof(AssemblyTitleAttribute);
    object[] c = _CurrentAssm.GetCustomAttributes(at, false);
    AssemblyTitleAttribute att =
       ((AssemblyTitleAttribute)(c[0]));
    return att.Title;
  }
}

public string Copyright
{
  get
  {
    Type at = typeof(AssemblyCopyrightAttribute);
    object[] c = _CurrentAssm.GetCustomAttributes(at, false);
    AssemblyCopyrightAttribute att =
      ((AssemblyCopyrightAttribute)(c[0]));
    return att.Copyright;
  }
}

public string Version
{
  get
  {
    AssemblyName an = new AssemblyName(_CurrentAssm.FullName);
    return an.Version.ToString();
  }
}

Operating System Name and Version

To retrieve the operating system name and version, it is the same as in any .NET application. You will use the Environment class and the associated properties on that class.

public string OSVersion
{
  get
  {
    return Environment.OSVersion.ToString();
  }
}

public string OSName
{
  get
  {
    string ret = string.Empty;

    switch (Environment.OSVersion.Version.Major)
    {
      case 7:
        ret = "Windows 8";
        break;
      case 6:
        if (Environment.OSVersion.Version.Minor == 0)
          ret = "Windows Vista";
        else if (Environment.OSVersion.Version.Minor == 1)
          ret = "Windows 7";
        break;
      case 5:
        if (Environment.OSVersion.Version.Minor == 0)
          ret = "Windows 2000";
        else if (Environment.OSVersion.Version.Minor == 1)
          ret = "Windows XP";
        break;
      case 4:
        ret = "Windows NT";
        break;
      default:
        ret = "Unknown Version";
        break;
    }

    return ret;
  }
}

The Current URL

A useful property in your application is finding out what the current URL is that is running your Silverlight user control. This is very easy to get at using the System.Windows.Browser.HtmlPage class. You access the Document.DocumentUri property to retrieve the current URL that is running on the user’s machine.

public string CurrentUrl
{
  get
  {
    try
    {
      return HtmlPage.Document.DocumentUri.ToString();
    }
    catch
    {
      return string.Format(_ERROR_MSG, "Current URL");
    }
  }
}

Get the Stack Trace

When you need to debug an application, having access to the stack trace is very helpful. Getting the stack trace in a Silverlight client-side user control is accomplished using the StackFrame class. If you get an exception in your application, the Exception object you get has a StackTrace property that will return your stack trace that got you to your exception. However, if you are not in an exception and just want to get the stack trace information, you write code like that shown in the GetStackTrace() method below.

public string GetStackTrace()
{
  StringBuilder sb = new StringBuilder(512);
  int loop = 0;
  string comma = string.Empty;
  string nameToMatch = MainAssemblyName;

  try
  {
    StackFrame sf = new StackFrame(loop);
    if (sf.GetMethod() != null)
      sb.Append("{");

    while (sf.GetMethod() != null)
    {
      // Get methods contained in this assembly only.
      if (sf.GetMethod().DeclaringType.Assembly.
           FullName.Equals(nameToMatch))
      {
        sb.Append(comma + sf.GetMethod().Name);
        comma = ",";
      }

      loop++;
      sf = new System.Diagnostics.StackFrame(loop);
    }
    if (sb.Length > 0)
      sb.Append("}");
  }
  catch
  {
    sb.AppendFormat(_ERROR_MSG, "Stack Trace");
  }

  return sb.ToString();
}

If you simply loop through all methods contained in the StackFrame you will get a lot of methods that are part of Silverlight and not your application. In this method you simply check to see if the methods are contained only in the main assembly name. This will probably work fine for a simple Silverlight application, but you may need to expand on this method if you have many client-side DLLs and wish to use this method when you are within any of those other DLLs.

Summary

There are a couple of other properties in the class that you can look at when you download the source code. This class will give you a lot of information that you will find useful when logging or creating an About page for your application. There is also a method named GetAllSystemInfo() that can be used to concatenate all of these properties together into one string. This method is great for logging all of these properties into a file. I will cover a client-side logging utility for Silverlight in my next blog post.

NOTE: You can download the sample code for this article by visiting my website at http://www.pdsa.com/downloads. Select “Tips & Tricks”, then select “Retrieve System Information in Silverlight” from the drop down list.

 

Dynamic Search with LINQ, the Entity Framework and Silverlight – Part 2

After my previous blog post, I realized that using SQL strings is not a great way to do things. Sometimes we start blogging too quick and then realize our mistakes after. But, no big deal, live and learn... I am going to now rewrite this application and use some lambda expressions to solve the problems inherit with concatenating strings to SQL statements; namely escaping a single quote and SQL Injection attacks. I am going to use the same search screen shown in Figure 1.

Figure 1: Search Screen

Figure 1: A search screen where the user can select an operation and a value for the searching on multiple fields.

Read the first blog post to see the calls to the WCF service. However, I want to know show the revised code to build a dynamic WHERE clause.

C#
public List<Customer> GetCustomers(string cname, string cnameOperator, string email, string emailOperator)
{
  AdventureWorksLTEntities db =
    new AdventureWorksLTEntities();

  var query = from cust in db.Customers select cust;

  if (string.IsNullOrEmpty(cname) == false)
  {
    switch (cnameOperator.ToLower())
    {
      case "equal to":
        query = query.Where(cust =>
                 cust.CompanyName.Equals(cname));
        break;
      case "starts with":
        query = query.Where(cust =>
                 cust.CompanyName.StartsWith(cname));
        break;
      case "contains":
        query = query.Where(cust =>
                 cust.CompanyName.Contains(cname));
        break;
    }
  }
  if (string.IsNullOrEmpty(email) == false)
  {
    switch (emailOperator.ToLower())
    {
      case "equal to":
        query = query.Where(cust =>
                 cust.EmailAddress.Equals(email));
        break;
      case "starts with":
        query = query.Where(cust =>
                 cust.EmailAddress.StartsWith(email));
        break;
      case "contains":
        query = query.Where(cust =>
                 cust.EmailAddress.Contains(email));
        break;
    }
  }

  query = query.OrderBy(cust => cust.CompanyName);

  return query.ToList();
}

VB
Public Function GetCustomers(cname As String, _
 cnameOperator As String, email As String, _
 emailOperator As String) As List(Of Customer) _
 Implements ICustomerSearch.GetCustomers
  Dim db As New AdventureWorksLTEntities

  Dim query = From cust In db.Customers Select cust

  If String.IsNullOrEmpty(cname) = False Then
    Select Case cnameOperator.ToLower()
      Case "equal to"
        query = query.Where(Function(cust) _
                 cust.CompanyName.Equals(cname))

      Case "starts with"
        query = query.Where(Function(cust) _
                 cust.CompanyName.StartsWith(cname))

      Case "contains"
        query = query.Where(Function(cust) _
                 cust.CompanyName.Contains(cname))

    End Select
  End If
  If String.IsNullOrEmpty(email) = False Then
    Select Case emailOperator.ToLower()
      Case "equal to"
        query = query.Where(Function(cust) _
                 cust.EmailAddress.Equals(email))

      Case "starts with"
        query = query.Where(Function(cust) _
                 cust.EmailAddress.StartsWith(email))

      Case "contains"
        query = query.Where(Function(cust) _
                 cust.EmailAddress.Contains(email))

    End Select
  End If

  query = query.OrderBy(Function(cust) cust.CompanyName)

  Return query.ToList()
End Function

As you can see in the above code you can simply use the Where() function on your IQueryable query to add WHERE clauses that get submitted to the back end database. It is always a good idea to turn on your SQL Profiler and check out the SQL that gets submitted to the back end database.

Summary

The advantage to this approach is now you are relying on the Entity Framework to handle escaping single quotes and avoiding the SQL injection attacks that you would otherwise have to handle. I hope this shows you something useful that you can use in your applications.

NOTE: You can download the sample code for this article by visiting my website at http://www.pdsa.com/downloads. Select “Tips & Tricks”, then select “Dynamic Search with LINQ, the Entity Framework and Silverlight – Part 2” from the drop down list.

 

Dynamic Search with LINQ, the Entity Framework and Silverlight

I have been helping a client with a Silverlight application and one of his requirements was to allow his users to be able to query 1 to 5 fields and use different operators for each field. For example, they can choose to search for a Company Name that “Starts With” a certain value and also search for an Email field that “Contains” another value. You can see an example of this search screen in Figure 1.

Figure 1: A search screen

Figure 1: A search screen where the user can select an operation and a value for the searching on multiple fields.

To make this search screen work you must pass two values for each search parameter you want to use. You need the operator to use and the value to search for. In this example I pass 4 parameters to a WCF Service. You might modify this method to pass in a collection of objects that contain the different values for each search.

In the code listed below you can see the Click event procedure behind the Search button on the screen. I did not use a View Model for this simple example since the point of this blog has to do with a dynamic LINQ search on the back end, but feel free to add your own View Model class.

C#
private CustomerSearchClient _Client = null;

private void btnGetCustomers_Click(object sender,
 RoutedEventArgs e)
{
  _Client = new CustomerSearchClient();

  _Client.GetCustomersCompleted += new
      EventHandler<GetCustomersCompletedEventArgs>
       (_Client_GetCustomersCompleted);

  _Client.GetCustomersAsync(txtCompanyName.Text,
        ((ComboBoxItem)cboCompanyOperator.SelectedItem)
            .Content.ToString(),
        txtEmail.Text,
        ((ComboBoxItem)cboEmailOperator.SelectedItem)
            .Content.ToString());
}

void _Client_GetCustomersCompleted(object sender,
 GetCustomersCompletedEventArgs e)
{
  lstCustomers.DataContext = e.Result;

  _Client.CloseAsync();
}

Visual Basic
Private WithEvents _Client As CustomerSearchClient

Private Sub btnGetCustomers_Click(sender As System.Object, _
  e As System.Windows.RoutedEventArgs) _
   Handles btnGetCustomers.Click
  _Client = New CustomerSearchClient()

  _Client.GetCustomersAsync(txtCompanyName.Text, _
           DirectCast(cboCompanyOperator.SelectedItem, _
              ComboBoxItem).Content.ToString(), _
           txtEmail.Text, _
           DirectCast(cboEmailOperator.SelectedItem, _
              ComboBoxItem).Content.ToString())
End Sub

Private Sub _Client_GetCustomersCompleted(sender As Object, _
 e As _
    CustomerServiceReference.GetCustomersCompletedEventArgs) _
      Handles _Client.GetCustomersCompleted
  lstCustomers.DataContext = e.Result

  _Client.CloseAsync()
End Sub

In the code above you create an instance of a WCF Service reference that calls the method named GetCustomers(). This method takes the company name value, the operator for how to search for the company name, the email value and the operator for how to search for the email. These four values are simply taken from the appropriate controls on this Silverlight user control.

Building the Dynamic LINQ Search

To dynamically build a LINQ search from the 4 values passed into the WCF Service you add an ADO.NET Entity Data Model to query against. In this sample I used the AdventureWorksLT database and added the Customer table to my Entity Data Model. I named this Entity Data Model AdvWorks. I then built a WCF Service named CustomerSearch and added the GetCustomers() method with the 4 parameters. You will need to add a using/Imports to the System.Data.Objects namespace in order to use the ObjectQuery class.

The ObjectQuery class allows you to use your Entity Framework context classes within a string to express your query. The complete code for the GetCustomers() method is listed further below, but let me give you just a simple little sample of how this works. Take the example below:

C#
AdventureWorksLTEntities db =
  new AdventureWorksLTEntities();

ObjectQuery<Customer> query = null;

sql = "SELECT VALUE cust FROM
         AdventureWorksLTEntities.Customers As cust ";
sql += " ORDER BY cust.CompanyName";

query = db.CreateQuery<Customer>(sql);

Visual Basic
Dim db As New AdventureWorksLTEntities

Dim query As ObjectQuery(Of Customer)

sql = "SELECT VALUE cust FROM
         AdventureWorksLTEntities.Customers As cust "
sql &= " ORDER BY cust.CompanyName"

query = db.CreateQuery(Of Customer)(sql)

In the above code you use the AdventureWorksLTEntities class which is created by the Entity Framework when you add a Data Model to the AdventureWorksLT database. A Customers collection object is created within this class to hold a collection of Customer objects. You must use these names within your string object. You also need to use the keyword “VALUE” followed by an alias name, as I used “cust” in the above example. If you will need to reference any specific column names within a WHERE clause or an ORDER BY clause you will reference those column names using this alias.

Once you have created the SQL string you use your AdventureWorksLTEntities object, the variable db in the code above, and call the CreateQuery() method passing in the SQL string you created. This will build a collection of Customer objects by executing this query against the database. You can view the query that is expressed by turning on the SQL Profiler and tracing any T-SQL calls to the database.

The complete GetCustomers() method builds the SQL statement dynamically by checking if the company name parameter or the email parameter is filled in. If they are filled in then an appropriate WHERE clause is added to the SELECT statement. You can now look at the complete GetCustomers() method below:

C#
using System.Collections.Generic;
using System.Data.Objects;
using System.Linq;

public class CustomerSearch : ICustomerSearch
{
  public List<Customer> GetCustomers(string cname,
     string cnameOperator,
     string email,
     string emailOperator)
  {
    AdventureWorksLTEntities db =
       new AdventureWorksLTEntities();
    string join = " WHERE ";
    string sql = null;
    ObjectQuery<Customer> query = null;

    sql = "SELECT VALUE cust FROM
           AdventureWorksLTEntities.Customers As cust ";

    if (string.IsNullOrEmpty(cname) == false)
    {
      sql += join + " cust.CompanyName " +
             BuildWhere(cnameOperator, cname);
      join = " AND ";
    }
    if (string.IsNullOrEmpty(email) == false)
    {
      sql += join + " cust.EmailAddress " +
             BuildWhere(emailOperator, email);
      join = " AND ";
    }

    sql += " ORDER BY cust.CompanyName";

    query = db.CreateQuery<Customer>(sql);

    return query.ToList();
  }

  public string BuildWhere(string operatorValue, string value)
  {
    string where = string.Empty;

    switch (operatorValue.ToLower())
    {
      case "equal to":
        where = " = '" + value + "'";
        break;
      case "starts with":
        where = " LIKE '" + value + "%'";
        break;
      case "contains":
        where = " LIKE '%" + value + "%'";
        break;
    }

    return where;
  }
}

Visual Basic
Imports System.Data.Objects

Public Class CustomerSearch
  Implements ICustomerSearch

  Public Function GetCustomers(cname As String, _
        cnameOperator As String, _
        email As String, _
        emailOperator As String) As List(Of Customer) _
          Implements ICustomerSearch.GetCustomers

    Dim db As New AdventureWorksLTEntities
    Dim join As String = " WHERE "
    Dim sql As String
    Dim query As ObjectQuery(Of Customer)

    sql = "SELECT VALUE cust FROM
           AdventureWorksLTEntities.Customers As cust "

    If String.IsNullOrEmpty(cname) = False Then
      sql &= join & " cust.CompanyName " & _
             BuildWhere(cnameOperator, cname)
      join = " AND "
    End If
    If String.IsNullOrEmpty(email) = False Then
      sql &= join & " cust.EmailAddress " & _
             BuildWhere(emailOperator, email)
      join = " AND "
    End If

    sql &= " ORDER BY cust.CompanyName"

    query = db.CreateQuery(Of Customer)(sql)

    Return query.ToList()
  End Function

  Public Function BuildWhere(operatorValue As String, _
      value As String) As String
    Dim where As String = String.Empty

    Select Case operatorValue.ToLower()
      Case "equal to"
        where = " = '" & value & "'"

      Case "starts with"
        where = " LIKE '" & value & "%'"

      Case "contains"
        where = " LIKE '%" & value & "%'"

    End Select

    Return where
  End Function
End Class

To build the WHERE clause you notice that I pass in the operator such as “Equal To”, “Starts With”, or “Contains” to a method called BuildWhere(). This method builds the expression for the WHERE clause. If the value of the operator is “Equal To”, then the equal sign (=) followed by the exact value typed into the text box wrapped into single quotes is returned. If the operator passed in is “Starts With”, then a LIKE operator followed by a single quote, the value typed into the text box, and a percent sign (%) and a closing single quote is returned. It the operator is “Contains”, then a percent sign is wrapped on both sides of the value typed into the text box with a LIKE operator.

All of this will build a SELECT statement that might look like one the following:

SELECT VALUE cust
   FROM AdventureWorksLTEntities.Customers As cust 
   WHERE  cust.CompanyName  LIKE 'a%'
   ORDER BY cust.CompanyName

or

SELECT VALUE cust
   FROM AdventureWorksLTEntities.Customers As cust 
   WHERE  cust.CompanyName  LIKE '%a%'
   AND    cust.EmailAddress LIKE 'o%'
   ORDER BY cust.CompanyName

or

SELECT VALUE cust
   FROM AdventureWorksLTEntities.Customers As cust 
   WHERE  cust.EmailAddress  LIKE 'a%'
   ORDER BY cust.CompanyName

Summary

While there are other approaches to this problem, I really like this one, because it helps me control the SQL that the Entity Framework submits to the back end database. When using LINQ, sometimes the SQL that the Entity Framework can be pretty convoluted. Using the CreateQuery() method I can sometimes craft the SQL a little closer to what will be eventually submitted to the back end and this can really improve the performance in a lot of cases. I hope you will find this little trick helpful.

NOTE: You can download the sample code for this article by visiting my website at http://www.pdsa.com/downloads. Select “Tips & Tricks”, then select “Dynamic Search with LINQ, the Entity Framework and Silverlight” from the drop down list.

 

Silverlight Tree View with Multiple Levels

There are many examples of the Silverlight Tree View that you will find on the web, however, most of them only show you how to go to two levels. What if you have more than two levels? This is where understanding exactly how the Hierarchical Data Templates works is vital. In this blog post, I am going to break down how these templates work so you can really understand what is going on underneath the hood. To start, let’s look at the typical two-level Silverlight Tree View that has been hard coded with the values shown below:

<sdk:TreeView>
  <sdk:TreeViewItem Header="Managers">
    <TextBlock Text="Michael" />
    <TextBlock Text="Paul" />
  </sdk:TreeViewItem>
  <sdk:TreeViewItem Header="Supervisors">
    <TextBlock Text="John" />
    <TextBlock Text="Tim" />
    <TextBlock Text="David" />
  </sdk:TreeViewItem>
</sdk:TreeView>

Figure 1 shows you how this tree view looks when you run the Silverlight application.

Figure 1: A hard-coded, two-level Tree View

Figure 1: A hard-coded, two level Tree View.

Next, let’s create three classes to mimic the hard-coded Tree View shown above. First, you need an Employee class and an EmployeeType class. The Employee class simply has one property called Name. The constructor is created to accept a “name” argument that you can use to set the Name property when you create an Employee object.

public class Employee
{
  public Employee(string name)
  {
    Name = name;
  }

  public string Name { get; set; }
}

Finally you create an EmployeeType class. This class has one property called EmpType and contains a generic List<> collection of Employee objects. The property that holds the collection is called Employees.

public class EmployeeType
{
  public EmployeeType(string empType)
  {
    EmpType = empType;
    Employees = new List<Employee>();
  }

  public string EmpType { get; set; }
  public List<Employee> Employees { get; set; }
}

Finally we have a collection class called EmployeeTypes created using the generic List<> class. It is in the constructor for this class where you will build the collection of EmployeeTypes and fill it with Employee objects:

public class EmployeeTypes : List<EmployeeType>
{
  public EmployeeTypes()
  {
    EmployeeType type;
       
    type = new EmployeeType("Manager");
    type.Employees.Add(new Employee("Michael"));
    type.Employees.Add(new Employee("Paul"));
    this.Add(type);

    type = new EmployeeType("Project Managers");
    type.Employees.Add(new Employee("Tim"));
    type.Employees.Add(new Employee("John"));
    type.Employees.Add(new Employee("David"));
    this.Add(type);
  }
}

You now have a data hierarchy in memory (Figure 2) which is what the Tree View control expects to receive as its data source.

Figure 2: A hierachial data structure of Employee Types containing a collection of Employee objects.

Figure 2: A hierachial data structure of Employee Types containing a collection of Employee objects.

To connect up this hierarchy of data to your Tree View you create an instance of the EmployeeTypes class in XAML as shown in line 13 of Figure 3. The key assigned to this object is “empTypes”. This key is used as the source of data to the entire Tree View by setting the ItemsSource property as shown in Figure 3, Callout #1.

Figure 3: You need to start from the bottom up when laying out your templates for a Tree View.

Figure 3: You need to start from the bottom up when laying out your templates for a Tree View.

The ItemsSource property of the Tree View control is used as the data source in the Hierarchical Data Template with the key of employeeTypeTemplate. In this case there is only one Hierarchical Data Template, so any data you wish to display within that template comes from the collection of Employee Types. The TextBlock control in line 20 uses the EmpType property of the EmployeeType class. You specify the name of the Hierarchical Data Template to use in the ItemTemplate property of the Tree View (Callout #2).

For the second (and last) level of the Tree View control you use a normal <DataTemplate> with the name of employeeTemplate (line 14). The Hierarchical Data Template in lines 17-21 sets its ItemTemplate property to the key name of employeeTemplate (Line 19 connects to Line 14). The source of the data for the <DataTemplate> needs to be a property of the EmployeeTypes collection used in the Hierarchical Data Template. In this case that is the Employees property. In the Employees property there is a “Name” property of the Employee class that is used to display the employee name in the second level of the Tree View (Line 15).

What is important here is that your lowest level in your Tree View is expressed in a <DataTemplate> and should be listed first in your Resources section. The next level up in your Tree View should be a <HierarchicalDataTemplate> which has its ItemTemplate property set to the key name of the <DataTemplate> and the ItemsSource property set to the data you wish to display in the <DataTemplate>. The Tree View control should have its ItemsSource property set to the data you wish to display in the <HierarchicalDataTemplate> and its ItemTemplate property set to the key name of the <HierarchicalDataTemplate> object. It is in this way that you get the Tree View to display all levels of your hierarchical data structure.

Three Levels in a Tree View

Now let’s expand upon this concept and use three levels in our Tree View (Figure 4). This Tree View shows that you now have EmployeeTypes at the top of the tree, followed by a small set of employees that themselves manage employees. This means that the EmployeeType class has a collection of Employee objects. Each Employee class has a collection of Employee objects as well.

Figure 4: When using 3 levels in your TreeView you will have 2 Hierarchical Data Templates and 1 Data Template.

Figure 4: When using 3 levels in your TreeView you will have 2 Hierarchical Data Templates and 1 Data Template.

The EmployeeType class has not changed at all from our previous example. However, the Employee class now has one additional property as shown below:

public class Employee
{
  public Employee(string name)
  {
    Name = name;
    ManagedEmployees = new List<Employee>();
  }

  public string Name { get; set; }
  public List<Employee> ManagedEmployees { get; set; }
}

The next thing that changes in our code is the EmployeeTypes class. The constructor now needs additional code to create a list of managed employees. Below is the new code.

public class EmployeeTypes : List<EmployeeType>
{
  public EmployeeTypes()
  {
    EmployeeType type;
    Employee emp;
    Employee managed;

    type = new EmployeeType("Manager");
    emp = new Employee("Michael");
    managed = new Employee("John");
    emp.ManagedEmployees.Add(managed);
    managed = new Employee("Tim");
    emp.ManagedEmployees.Add(managed);
    type.Employees.Add(emp);

    emp = new Employee("Paul");
    managed = new Employee("Michael");
    emp.ManagedEmployees.Add(managed);
    managed = new Employee("Sara");
    emp.ManagedEmployees.Add(managed);
    type.Employees.Add(emp);
    this.Add(type);

    type = new EmployeeType("Project Managers");
    type.Employees.Add(new Employee("Tim"));
    type.Employees.Add(new Employee("John"));
    type.Employees.Add(new Employee("David"));
    this.Add(type);
  }
}

Now that you have all of the data built in your classes, you are now ready to hook up this three-level structure to your Tree View. Figure 5 shows the complete XAML needed to hook up your three-level Tree View. You can see in the XAML that there are now two Hierarchical Data Templates and one Data Template. Again you list the Data Template first since that is the lowest level in your Tree View. The next Hierarchical Data Template listed is the next level up from the lowest level, and finally you have a Hierarchical Data Template for the first level in your tree. You need to work your way from the bottom up when creating your Tree View hierarchy. XAML is processed from the top down, so if you attempt to reference a XAML key name that is below where you are referencing it from, you will get a runtime error.

Figure 5: For three levels in a Tree View you will need two Hierarchical Data Templates and one Data Template.

Figure 5: For three levels in a Tree View you will need two Hierarchical Data Templates and one Data Template.

Each Hierarchical Data Template uses the previous template as its ItemTemplate. The ItemsSource of each Hierarchical Data Template is used to feed the data to the previous template. This is probably the most confusing part about working with the Tree View control. You are expecting the content of the current Hierarchical Data Template to use the properties set in the ItemsSource property of that template. But you need to look to the template lower down in the XAML to see the source of the data as shown in Figure 6.

Figure 6: The properties you use within the Content of a template come from the ItemsSource of the next template in the resources section.

Figure 6: The properties you use within the Content of a template come from the ItemsSource of the next template in the resources section.

Summary

Understanding how to put together your hierarchy in a Tree View is simple once you understand that you need to work from the bottom up. Start with the bottom node in your Tree View and determine what that will look like and where the data will come from. You then build the next Hierarchical Data Template to feed the data to the previous template you created. You keep doing this for each level in your Tree View until you get to the last level. The data for that last Hierarchical Data Template comes from the ItemsSource in the Tree View itself.

NOTE: You can download the sample code for this article by visiting my website at http://www.pdsa.com/downloads. Select “Tips & Tricks”, then select “Silverlight TreeView with Multiple Levels” from the drop down list.

Override ToString() in your Classes

One of the reasons I love teaching is because of the questions that I get from attendees. I was giving a presentation at DevConnections and was showing a collection of Product objects. When I hovered over the variable that contained the collection, it looked like Figure 2. As you can see in the collection, I have actual product names of my videos from www.pdsa.com/videos being displayed. To get your data to appear in the data tips you must override the ToString() method in your class.

To illustrate this, take the following simple Product class shown below:

public class Product
{
  public string ProductName { get; set; }
  public int ProductId { get; set; }
}

This class does not have an override of the ToString() method so if you create a collection of Product objects you will end up with data tips that look like Figure 1. Below is the code I used to create a collection of Product objects. I have shortened the code in this blog, but you can get the full source code for this sample by following the instructions at the bottom of this blog entry.

List<Product> coll = new List<Product>();
Product prod;

prod = new Product()
  { ProductName = "From Zero to HTML 5 in 60 Minutes",
    ProductId = 1 };
coll.Add(prod);
prod = new Product()
  { ProductName = "Architecting Applications …",
    ProductId = 2 };
coll.Add(prod);
prod = new Product()
  { ProductName = "Introduction to Windows Phone Development",
    ProductId = 3 };
coll.Add(prod);
prod = new Product()
  { ProductName = "Architecting a Business  …",
    ProductId = 4 };
coll.Add(prod);
...
...

Figure 1: Class without Overriding ToString() 

Figure 1: Class without overriding ToString()

Now, go back to the Product class and add an override of the ToString() method as shown in the code listed below:

public class Product
{
  public string ProductName { get; set; }
  public int ProductId { get; set; }

  public override string ToString()
  {
    return ProductName;
  }
}

In this simple sample, I am just returning the ProductName property. However, you can create a whole string of information if you wish to display more data in your data tips. Just concatenate any properties you want from your class and return that string.

When you now run the application and hover over the collection object you will now see something that looks like Figure 2.

Figure 2: Overriding ToString() in your Class

Figure 2: Overriding ToString() in your Class

Another place the ToString() override comes in handy is if you forget to use a DisplayMemberPath in your ListBox or ComboBox. The ToString() method is called automatically when a class is bound to a list control.

Summary

You should always override the ToString() method in your classes as this will help you when debugging your application. Seeing relevant data immediately in the data tip without having to drill down one more layer and maybe scroll through a complete list of properties should help speed up your development process.

NOTE: You can download the sample code for this article by visiting my website at http://www.pdsa.com/downloads. Select “Tips & Tricks”, then select “Override ToString” from the drop down list.

 

Posted: Mar 28 2012, 07:38 AM by psheriff | with 2 comment(s)
Filed under: , ,
Call for Speakers - DevConnections Fall 2012

Calling all Speakers!

My name is Paul Sheriff and I am one of the conference chairs for DevConnections in the Fall of 2012 which will be held in Las Vegas from Oct. 29-Nov 1, 2012. This show will focus on Visual Studio 11 and Windows 8 development, but good generic topics on .NET development are still welcome. You need to have 3 topics accepted in order to be compensated for your travel and sessions. Thus, you will need to submit more than 3 topics.

Fundamentals Track

I need speakers that are adept at teaching business application programmers how to move to .NET, XAML, Windows 8 Metro, HTML5, JavaScript and JQuery. I am not looking for a re-hash of old seminar topics. I want new "step-by-step" oriented seminars that show people how to do one or two things well in Visual Studio 2010 or Visual Studio 11. I would really like step-by-step seminars as much as possible. I am especially interested in those seminars that show people how to move from old style programming to new style programming (Synchronous to Asynchronous, Web API, SOA, XAML, HTML5, etc.) I am looking for those seminars that teach the basics to business programmers across a wide variety of topics. Below are the technologies/areas that I think would be good for this track.

• Developing an App in Windows 8 Metro
• Creating a multi-tier app using the new Web API
• Using HTML 5 for Mobile Applications
• Getting Started with JavaScript and jQuery
• Moving from Synchronous programming to Asynchronous
• Suggest a topic…

Professional Development Track

This track will focus on the programmer who is moving up to architect, project manager or a development manager. The intent is to present a series of seminars that will help them build their skills in these areas.

• Project Management
• Requirements Gathering
• Estimating
• Architecture
• Suggest a topic…

*** NOTE: NEW SESSIONS NEEDED!!! ***

IMPORTANT: We want fresh sessions! If you have presented a topic at DevConnections more than 2 times before, please do not submit those as we will not accept them. We will really be interested in topics around Windows 8, Metro, HTML5 and JavaScript and JQuery.

If you are interested, please let me know by emailing me directly at PSheriff@pdsa.com. Here is what I need from you ASAP!

1. A title and short description of your proposed topics
2. Your willingness to present on a minimum of 3 topics
3. You are able to come Oct. 29-Nov. 1, 2012 to Las Vegas to speak on your topics
4. DEADLINE!  I need all of this by April 3, 2012

Please enter your abstracts at http://www.deeptraining.com/devconnections/abstracts

Abstract Format

Please really think about your Title and Abstract. I would prefer you to have it in the following format.
 
Title: The title should be very action oriented and explain exactly what you will get from this session. Think “Marketing and Sales”! You are selling your session to the attendees. Using numbers in your title are a great way to gather interest, for example; “Top 10 tips for ____”, “The 20 things you need to know to _____”, “You can learn _____ in just 75 minutes”, etc.

Description: Use a lot of action sentences and explain each demo and each point that the attendee will get from attending this seminar. Really sell this seminar to the attendee in here. If possible we would like to have the user walk away with a class, a DLL, a reusable widget, flash cards, a document with step-by-step instructions, or a set of concrete techniques from this session. Give some value to the attendee. Make this “Take Away” the last sentence in your abstract.

Please keep the abstracts under 200 words each and in one paragraph. No bulleted items and line breaks, and please use a spell-checker. You need to use the web-based tool to submit them officially, but send to me too please. Please submit at least 3 abstracts, but it would help your chances of being selected if you submitted 5 or more abstracts. Also, you are encouraged to suggest all-day pre or post conference workshops as well. We need to finalize the conference content and the tracks layout in just a few weeks, so we need your abstracts no later than April 3, 2012. NO EXECPTION will be granted on late submissions!

What you will get if selected:

• $500 per regular conference talk.
• Compensation for full-day workshops ranges from $500 for 1-20 attendees to $2500 for 200+ attendees.
• Airfare allowance of up to $500. If you are international, you will have to cover the rest.
• Hotel stay paid by the conference.
• Free admission to the conference.
• Lots of fun!

Posted: Mar 13 2012, 09:07 AM by psheriff | with no comments
Filed under: ,
An HTML 5 Navigation Screen

Like many people today, we are exploring HTML 5 for use in web applications. While not really ready for prime-time on its own at this point, it can definitely be used in combination with tools like Modernizr (www.Modernizr.com). One of the first things you might do is create a home page with a simple navigation system on it. This blog post will show you one way to accomplish this.

Navigation

Figure 1 shows an example of a home screen and a navigation system. One of the things you notice right away about this home screen in Figure 1 is the drop shadows around each navigation button. You also notice that each button has a rounded corner. All the buttons together sit atop a background that also has a drop shadow and also has a rounded corner. Further, each of these elements also has a gradient color of light gray to gray.

While there were ways to accomplish drop shadows, rounded corners and gradients prior to CSS 3 and HTML 5, it was not always easy for developers to do so. You typically needed help from a graphical artist to create these. These graphical elements are a part of CSS 3 and can be created by a developer with a little help from some on-line tools such as ColorZilla which I will talk about in the next section.

Figure 1: A navigation system in HTML 5 can be surrounded with <nav> tags.

Listing 1 shows the complete HTML for the navigation screen shown in Figure 1. As you can see the HTML is fairly simple. The new items in this HTML are the box-shadow, and the border-radius rules in the .mainMenu style selector, and the <nav> and <footer> elements in the main body of the HTML.

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>Business UI Samples</title>
  <link rel="stylesheet"
        type="text/css"
        href="Styles/Styles.css" />
  <style type="text/css">
    .mainMenu
    {
      color: White;
      float: none;
      text-decoration: none;
      display: inline-block;
      text-align: center;
      height: 0.5em;
      width: 5em;
      margin: 0.5em 0.5em 0.5em 0.5em;
      padding: 0.3em 1em 1.1em 1em;
      border: 0.09em solid black;
      box-shadow: 0.5em 0.5em rgba(0,0,0,0.8);
      -webkit-box-shadow: 0.5em 0.5em rgba(0,0,0,0.8);
      -moz-box-shadow: 0.5em 0.5em rgba(0,0,0,0.8);
      border-radius: 0.5em;
      -webkit-border-radius: 0.5em;
      -moz-border-radius: 0.5em;
    }
    
    p
    {
      margin-left: 1em;
    }
  </style>
</head>
<body>
  <nav class="backColor">
    <a href="Login.htm" class="mainMenu backColor">Login</a>
    <a href="ContactUs.htm"
       class="mainMenu backColor">Contact</a>
    <a href="Name.htm" class="mainMenu backColor">Name</a>
    <a href="Address.htm"
       class="mainMenu backColor">Address</a>
    <a href="User.htm" class="mainMenu backColor">User</a>
  </nav>
  <br />
  <br />
  <br />
  <p>
    Content goes in here...</p>
  <footer class="backColor">
  Samples of Business UI
  </footer>
</body>
</html>

Listing 1: The HTML for the default page of your web application.

The <nav> element is nothing more than a semantic markup used to group links together to make up your main navigation area. Having a separate element allows us to use an element selector in CSS to provide styling for <nav>. In addition, <nav> allows search engines to determine that this is your main navigation area.

The CSS rules “box-shadow” and “border-radius” used in the .mainMenu style are what provide the rounded corners of your main navigation area and footer area. The three different versions of box-shadow and border-radius help you account for the syntax differences between browsers. I have tested these styles with these browsers; Opera 11.61, Google Chrome 17.0, Safari 5.12, FireFox 9.01, and IE 9. While the screens in this article may look slightly different on each one, they all seem to work with HTML 5 and CSS 3. If the particular browser does not support a specific feature of HTML 5 or CSS 3 then they simply downgrade to something that is similar in HTML 4.

The other thing you may notice from the navigation screen shown in Figure 1 is the navigation background and the hyperlinks have a slight gradient color to them. In other words, they are not just one color of gray, but they start with a light gray at the top and gradually become a darker gray at the bottom. To accomplish this you add a class attribute to the <nav> button called “backColor”. This class style is defined in the style sheet named “Styles.css”. Listing 2 shows the complete definition of this “backColor” style. Now don’t let the size of this listing scare you. This was code generated from a great website called ColorZilla (http://www.colorzilla.com/). This free, on-line utility will generate the correct CSS styles needed to create gradients on each browser.

.backColor
{
  /* Old browsers */
  background: rgb(181,189,200);
  /* IE9 SVG, needs conditional override of
     'filter' to 'none' */
  background: url(data:image/svg+xml;base64, PD94bWwgdm …);
  /* FF3.6+ */
  background: -moz-linear-gradient(top,
              rgba(181,189,200,1) 0%,
              rgba(130,140,149,1) 36%,
              rgba(40,52,59,1) 100%);
  /* Chrome,Safari4+ */
  background: -webkit-gradient(linear, left top, left bottom,
              color-stop(0%, rgba(181,189,200,1)),
              color-stop(36%, rgba(130,140,149,1)),
              color-stop(100%, rgba(40,52,59,1)));
  /* Chrome10+,Safari5.1+ */
  background: -webkit-linear-gradient(top,
              rgba(181,189,200,1) 0%,
              rgba(130,140,149,1) 36%,
              rgba(40,52,59,1) 100%);
  /* Opera 11.10+ */
  background: -o-linear-gradient(top,
              rgba(181,189,200,1) 0%,
              rgba(130,140,149,1) 36%,
              rgba(40,52,59,1) 100%);
  /* IE10+ */
  background: -ms-linear-gradient(top,
              rgba(181,189,200,1) 0%,
              rgba(130,140,149,1) 36%,
              rgba(40,52,59,1) 100%);
  /* W3C */
  background: linear-gradient(top,
              rgba(181,189,200,1) 0%,
              rgba(130,140,149,1) 36%,
              rgba(40,52,59,1) 100%);
  /* IE6-8 */
  filter: progid:DXImageTransform.Microsoft.gradient(
              startColorstr='#b5bdc8',
              endColorstr='#28343b',
              GradientType=0 );
}

Listing 2: Gradients are a great way to make your screens look more natural to users.

The last new item on the home page is the <footer> element. Again, this is just a semantic markup element. You style <footer> exactly as you style the <nav> element. You will use the same class attribute, backColor, on this <footer> element. This adds the background color to the footer. Also, in the Styles.css you will find the footer selector defined like the following:

footer
{
  padding: 0.5em 0.5em 0.5em 0.5em;
  margin: 0.5em 0.5em 0.5em 0.5em;
  position: absolute;
  bottom: 0.2em;
  left: 0em;
  width: 95%;
  text-align: left;
  border-radius: 0.75em;
  -webkit-border-radius: 0.75em;
  -moz-border-radius: 0.75em;
}

The above rules are applied to the <footer> element and the backColor class is also applied with the background color. Keeping your background color separate from your other style rules allows you to change the background color in just one place without affecting any other style rules. You also see this type of styling on the <a href> elements used for the main navigation.

<a href="Login.htm" class="mainMenu backColor">Login</a>

In the class attribute on each of the <a href> elements you are applying two styles. The mainMenu selector controls foreground color, margin, padding and other rules while the backColor selector applies the background color.

Summary

In this blog post you learned to create a simple home page using the <nav> and <footer> elements in HTML 5. You also learned to use rounded borders and drop shadows will make your screens look more modern. Employing linear gradients in your background colors will help your applications look more natural to new users. Of course, all of this assumes that HTML 5 can be rendered on all browsers that your users use. Right now, this is just not the case. So, you will need to still use some fallback mechanisms such as Modernizr (www.modernizr.com) to ensure that your HTML 5 applications will still work with older browsers.

NOTE: You can download the sample code for this article by visiting my website at http://www.pdsa.com/downloads. Select “Tips & Tricks”, then select “HTML 5 Navigation” from the drop down list.

 

Posted: Mar 03 2012, 03:08 PM by psheriff | with 3 comment(s)
Filed under: ,
Wrapping up Configuration Manager

Many developers use the ConfigurationManager class to retrieve settings from the .Config file of your application. This class allows you to retrieve settings from the <appSettings> element. With just a single line of code as shown in the following line:

file = ConfigurationManager.AppSettings["CustomerFile"];

The above code assumes you have the following setting declared in your App.Config or Web.Config file for your application:

<configuration>
  <appSettings>
    <add key="CustomerFile"
         value="D:\Samples\Customers.xml" />
  </appSettings>
</configuration>

This works great except in the case where you misspell the key name in your line of code, or you forget to add the element in the <appSettings> element in your .Config file. In either case, the value you get back will be a null value. Sometimes these null values can wreak havoc on your code because you forgot to check the value for null and the attempt to perform some operation on that value such as opening the file name. For example, the following code would cause a ArgumentNullException to be raised because the key value is misspelled.

string value = string.Empty;

value = ConfigurationManager.AppSettings["CustomerFil"];

System.IO.File.OpenText(value);

To fix the above code you need to test the “value” variable to see it is null prior to attempting to open the file as shown in the following code:

string value = string.Empty;

value = ConfigurationManager.AppSettings["TheValue"];

if (value == null)
  MessageBox.Show("Can't open the file");
else
  System.IO.File.OpenText(value);

MessageBox.Show(value.ToString());

Another issue with the above code is if you wish to change the location of where you are storing your application settings, you have to modify every line of code throughout your whole application where you used ConfigurationManager.AppSettings. For example, sometime in the future you might want to store your settings in an XML file located on a central server, or maybe store them in a database. This would be a lot of extra work due to you probably have a lot of places where you are retrieving configuration settings. Instead let’s wrap up the calls to the ConfigurationManager.AppSettings method in your own class.

Wrap Up Configuration Manager

A best practice that I have employed for over twenty years has been to wrap up any method calls that could potentially change in the future. Configuration settings, database access calls, registry settings, WCF Services, and similar types of classes are all candidates for wrapping up. Creating your own class allows you to change the methods for getting data from another source without you having to change the code in your application.

For the configuration settings shown previously, creating a class to wrap up the call to ConfigurationManager.AppSettings is a very simple task. Below is the complete class that will allow you to get a string and an integer value from a configuration file.

public class AppConfig
{
  public string XmlPath { get; set; }
  public int DefaultType { get; set; }

  // Wrapper around ConfigurationManager.AppSettings call
  protected string GetSetting(string key)
  {
    return ConfigurationManager.AppSettings[key];
  }

  public string GetSetting(string key, string defaultValue)
  {
    string value;

    value = GetSetting(key);
    if (value == null)
      value = defaultValue;

    return value;
  }

  public int GetSetting(string key, int defaultValue)
  {
    int ret;
    string value;

    value = GetSetting(key);
    if (value == null)
      ret = defaultValue;
    else
      ret = Convert.ToInt32(value);

    return ret;
  }
}

Notice how each of the public GetSetting methods call a protected method named GetSetting where the call to ConfigurationManager.AppSettings is made. Now, if you want to store your configuration settings in a database table, you only need to change the protected GetSetting method. All of the rest of the methods in this class and the calls you make in your application to the GetSetting methods in this class do not need to change at all.

In addition to wrapping up the call to the ConfigurationManager.AppSettings method call, you can add on additional functionality as well. For instance you can allow the programmer to pass in a default value to return if the value is not found in your settings storage location.

You call the GetSetting methods in AppConfig class using the following code:

AppConfig config = new AppConfig();

config.XmlPath = config.GetSetting("XmlPath", @"C:\");

MessageBox.Show(config.XmlPath);

In the above code if the “XmlPath” key was not found, then C:\ would be returned. The same call can be used for the overloaded version of GetSetting that returns an integer value. You pass in an integer value that you wish to have returned if the key “DefaultType” is not found.

AppConfig config = new AppConfig();

config.DefaultType = config.GetSetting("DefaultType", 1);

MessageBox.Show(config.DefaultType.ToString());

Summary

Wrapping up calls to .NET classes and their methods can give you more flexibility in the future if you wish to change the implementation of a method. In addition it allows you to add on functionality that is not present in the original calls. Wrapping up methods like this also protects you from changes that Microsoft might introduce in future versions of the .NET Framework. If they obsolete a class or method, you now only need to change your code in just place. The rest of your application does not need to change. In other words, you are helping to future-proof your code.

NOTE: You can download this article and the sample code that goes with this blog entry at my website. http://www.pdsa.com/downloads. Select “Tips and Tricks”, then “Wrapping up Configuration Manager” from the drop down list.

Good Luck with your Coding,
Paul Sheriff

** SPECIAL OFFER FOR MY BLOG READERS **
We frequently offer a FREE gift for readers of my blog. Visit http://www.pdsa.com/Event/Blog for your FREE gift!

Posted: Feb 06 2012, 07:27 PM by psheriff | with 4 comment(s)
Filed under:
Architecting Applications for Multiple UIs video now available!

Just wanted to let everyone know that I published a new video this morning on "Architecting Applications for Multiple UIs". This $20 video is an hour long and includes 3 sample applications in WPF, ASP.NET and Windows Phone with a common set of class libraries and WCF Services. This video walks you through how to create a View Model to talk to WCF Services and this same View Model is then used from all three of these UIs. Doing this saves you from writing a ton of front-end code. In fact the code behind in most of these is less than 50 lines of code! If you are interested take a look here: http://www.pdsa.com/Products/ProductDetail.aspx?prod=423

Thanks,
Paul

Posted: Jan 19 2012, 01:59 PM by psheriff | with 1 comment(s)
Filed under: ,
More Posts Next page »