The Value of Converters

by mgordon 1. December 2009 05:55

Over time, I’ve discovered more and more uses for value converters in my Silverlight and WPF applications.  In this post, we’ll look at what they are and some scenarios where they are useful.

What are value converters

If you’ve done any development in Silverlight or WPF, you know that when using these technologies, the user interface is specified in XAML, a dialect of XML.  Since we are using XML, or essentially strings, to defined our GUI the XAML parser needs to know how to turn the strings we specify into types.  For example, when we specify at attribute on a control such as IsEnabled=”True”, there needs to be away for the string “True” to be understood as a Boolean value.  When we say Background=”Black”, the string “Black” needs to be understood as Brush of color #FF000000. 

Both of these examples are common occurrences so there are built in converters that take care of these.  However, in our applications, there are likely going to be cases where we need to specify a value that the XAML parser has no idea how to interpret.  For these cases, we can create our own value converter to specify what type a string needs to be converted to.

An Example

Suppose you have a DataGrid in your UI that contains orders.  Each of these orders has a status property and you want to display an icon in each row that depicts the status of the order.  The grid is bound to a collection in the ViewModel.  How do you achieve this?

 

First, you’d need to define the column for the icon.  Perhaps, something like below.

<data:DataGridTemplateColumn Header="Status" CellTemplate="{StaticResource statusTemplate}" 
                                            IsReadOnly="True" Width="50" 
                                            CanUserSort="False"/>

 

Here, we specify the column’s layout in a template, statusTemplate.

<DataTemplate x:Key="stausTemplate">
    <Image Height="32" Width="32" Source="{Binding StatusCode, Converter={StaticResource statusToImage}, 
        Mode=OneWay}"/>
</DataTemplate>

 

In our template, we’re specifying an Image element, but binding its Source property to the status code.  Somehow, that status code has to be converted into a reference to an image file.  To handle that conversion, we specify a converter in our binding.  Let’s look at how to implement that converter.

To start, we need to create a new class and have it implement the interface IValueConverter.  Our class would look like this.

public class StatusToImageConverter : IValueConverter
    {

        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, 
            System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }

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

        #endregion
    }

 

Implementing the IValueConverter interface requires us to implement two methods, Convert and ConvertBack.  The Convert method will be called to convert the original value to the desired value.  In our example, this method will be responsible for converting the status code to and image reference.  The ConvertBack method, does just the opposite.  If the converter is used in a TwoWay binding, the ConvertBack method will be called to convert a value specified back into a value of the original type.  In other words, if in our example the user were able to select an image, that image would be converted back into a status code before being pushed back into the order.

In our case, we’re only interested in using the converter in a OneWay binding, so we can leave the ConvertBack method un-implemented.  The finished class might look like the below.

public class StatusToImageConverter : IValueConverter
    {

        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, 
            System.Globalization.CultureInfo culture)
        {
            char statusCode = value.ToString()[0];

            switch (statusCode)
            {
                case 'A':
                    return "/Images/active.png";
                case 'W':
                    return "/images/working.png";
                case 'F':
                    return "/images/filled.png";
                case 'P':
                    return "/Images/paid.png";
            }

            return null;
        }

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

        #endregion
    }

 

With the converter built, we just need to reference it in our XAML as a resource.

<converters:StatusToImageConverter x:Key="statusToImage"/>

 

Other Uses

What if in our grid, we also have a column that contains a dropdown containing the shipper that we will be using to ship our order.  The ItemsSource for the dropdown is bound to a collection of Shipper objects and its SelectedValue property is bound to a ShipperId.  That shipperId needs to be converted into a Shipper object in order for the binding to work.  Using what we know about value converters, we can create a converter that takes the id and looks up the corresponding object in a list.

Converters are incredibly flexible and powerful allowing you to inject logic into your UI easily.     

Tags: ,

Silverlight | WPF

More about Silverlight RawFaults

by mgordon 31. July 2009 15:32

While writing the Silverlight applications at FunkyTools.com, I quickly found that not being able return exceptions from my WCF calls was a huge problem for me.  I located a solution that had been released by the Silverlight WCF team and, at the time, learned just enough about the code to get it integrated into my solution.  I documented how to use the code in a previous blog post. Recently, however, I’ve taken the time to dig into the code and learn more about how it works.

 

Why Faults Don’t Get Returned To Silverlight In The First Place

When Silverlight makes a WCF call, the communication with the server does not happen from the Silverlight application.  Rather, Silverlight uses the browser API to originate the call and the response comes back to the browser, first, and it passes it back to our application.  When an exception occurs in the WCF service, the return HTTP Response Code is changed from 200 to some other value to indicate the call was problematic.  If a response code other than 200 is returned to the browser, Silverlight gets handed back a “Not Found”" Exception from the browser and the actual exception information is lost.

 

The Sample Solution

The sample solution contains 4 projects.

  • SilverlightFaultBehavior – Defines a behavior that is added to a customer binding we can use to enable to have out exceptions returned.
  • SilverlightMessageInspector – Defines a new Channel and Binding for use in the solution.  This Project wires up the Channel, Binding,  and behavior.  These first two projects define all that’s needed to set up the server side of the functionality we desire.
  • SilverlightRawFaults – Defines a single class that is of interest which is a message inspector – more on this in a second.
  • SilverlightRawFaults.Web – A test web site to host the sample service.

 

SilverlightFaultBehavior Project

This project defines a single class, SilverlightFaultBehavior, which extends BehaviorExtensionElement and IEndPointBehavior.  Basically, it adds an additional behavior that we can tie to our bindings.  In this class, there is a method IDispatchMessageInspector.BeforeSendReply that contains the following code:

 

if (reply.IsFault)
{
   HttpResponseMessageProperty property = new HttpResponseMessageProperty();
   property.StatusCode = System.Net.HttpStatusCode.OK; // 200

   reply.Properties[HttpResponseMessageProperty.Name] = property;
}

 

So, basically, just before the response is returned to the browser, this behavior sets the return code to 200 if it’s any other value.

 

SilverlightMessageInspector Project

This project is basically a plumbing project.  It composes the behavior, channel and the message inspector into a binding, which when used, is pre-configured to return the exceptions we desire.

 

SilverlightRawFaults Project

This project contains file SilverlightFaultRawMessageInspector.cs and defines the two classes needed on the client side.  The file contains two classes; RawFaultException, a custom CommunicationException and SilverlightFaultMessageInspector which implements IClientMessageInspector.  In the latter of these classes a method, AfterReceiveReply, contains this code:

 

if (reply != null && reply.Version == MessageVersion.Soap11)
{
    if (reply.IsFault)
    {
        throw new RawFaultException(reply.GetReaderAtBodyContents());
    }
}

 

So, when the reply is received by Silverlight, but before it is returned to our application, this method checks to see if the reposonse contains a Soap 1.1 Fault and if it does, and instance of the custom CommunicationException is created that contains the fault details (error code, message and stack trace) and that exception instance is thrown into our application.

 

So, our response is inspected on the server and its response code is set back to 200 so the browser will interrupt the flow of our fault.  Once Silverlight gets the response, our client side message inspector checks to see if a fault is contained in the response and if so, the fault is converted into an exception and thrown back to the method in our application that originated the call.  

Tags: ,

.Net | Silverlight

Coloring a ListBoxItem In Silverlight

by mgordon 6. July 2009 10:47

I was recently trying to display ListBoxItems with different colors based on criteria in the items the list was bound to.  More specifically, the challenge was not in changing the background colors, but with getting the color to fill the entire item.  After much searching, I found a blog post, here, by Ric Robinson that reminded me that I already knew how to fix the problem.

 

Why Setting HorizontalContentAlignment Doesn’t Work

As Ric explains, in the default ControlTemplate the alignment for the item is hard coded to “Left” which means that no matter what you do with the properties of the ListBox or ListBoxItem, the contents of the item will never stretch to fill the container.

 

The Solution

Since Silverlight allows you to override the style of any control, the solution is to create a style that is an exact copy of the default style and modify the HorizontalAlignment property to bind to the HorizontalContentAlignment value specified on the ListBox.  While I was at it, I modified several of the style attributes to suit my liking.

Tags:

Silverlight

Funkytools.com is Live

by mgordon 28. June 2009 10:18

I’ve been working for months on a Silverlight application for task management that draws from the Getting Things Done philosophy among others.  I’ve created a web site to host the application at http://www.funkytools.com.  If you get the chance and are so inclined, check it out.

Tags: ,

General | Silverlight

Access Role Provider from ASP.Net Ajax and Silverlight

by mgordon 19. June 2009 05:00

In an earlier postI detailed how to access the Membership provider’s services from Silverlight and ASP.Net Ajax.  This is great for logging users into your site, but what if you want to make only certain parts of the application available to these users based on their role in the system at the time they log in or just check the user’s role before allowing them to perform an action? 

I found a great post by Satheesh Babu that describes how to access the Role provider from within the browser. 

Tags:

.Net | ASP.Net | Silverlight

The Best Service Reference Strategy for Silverlight

by mgordon 12. June 2009 06:08

When first learning Silverlight, having often utilized the “Add Web Reference” functionality in Visual Studio in days gone by, I reached for the alluring “Add Service Reference” functionality when adding references to WCF services to my Silverlight projects. I encountered a few problems using this approach and began to search for a better way to reference WCF services.

Project Bloat

The first problem I noticed was the sheer number of files generated by Visual Studio when you add a service reference.  If you’re using source control (and you should be), any modification made to a service reference is going to delete several files and replace them with new ones.  When checking these changes into source control, it can sometimes be confusing trying to figure out how to get your source checked in in a valid state.

Reusing Referenced Assemblies

Second problem I found I was having was that I was often getting errors and warnings when adding or modifying a service reference.  These came in different flavors, but most all complained about the format of the WSDL being received from the service.  With some trial and error, I figured out that the problems were being caused by the default behavior of Visual Studio when adding a reference in respect to reusing types in referenced assemblies. When adding a service reference, the below dialog appears.

AddRef

If you click on the Advanced button, this dialog appears.

Advanced

By default, the “Reuse types in referenced assemblies” checkbox is checked and the “Reuse types in all referenced assemblies” radio button is selected.  If you’re having problems getting client proxies to generate for your services, try clearing the checkbox as this seemed to be the solution for me.

Location, Location, Location

The third problem I’ve had with adding references this way is probably the most important.  With the Add Web Reference I knew and loved, it was a fairly simple matter to modify the generated Reference.cs file to pull the URL for the web service endpoint from a configuration file.  But, when adding a service reference with visual studio, whatever endpoint you specify when adding the reference gets scattered through various of the generated files which makes manual modification extremely difficult.

When I’m working with a Silverlight project, I typically like to have all the services running locally while I’m developing to facilitate debugging and modification of the services which means that my service references need to be pointing to localhost.  Before I deploy, I have to go to each reference and reconfigure it to point to the production server which means that any modified version of my services have to already exist on the server and all this makes deployment a huge headache.  If my shop employed a full set of environments - dev, QA, staging, prod – I’m sure I’d go postal.

The Search for a Better Way

In thinking about the problem, I realized that what I needed was a simple way to generate a client proxy.  I could then build my address, binding and channel in code, pulling any of the necessary pieces of configuration from a config file.  My first thought was to create the proxy class using SvcUtil.exe.  I soon found, though, that the proxies generated by this tool are incompatible with Silverlight.  I then found out about a tool called SlSvcUtil.exe that generates proxies specifically for Silverlight.  Unfortunately, this tool is supposed to ship with Silverlight 3 and I’m still working in version 2.

For now, I’ve found two alternatives.  First is a bit of a hack, but still a fairly easy way to generate proxies that I found here.  Basically, this blog post suggests using the “Add Service Reference” functionality in Visual Studio to generate a reference.cs, saving that class and then deleting the service reference.  I also found an article by David Betz, here, that takes you through an excellent explanation of the details of the inner workings of WCF with Silverlight and suggests writing proxies by hand.

It’s good to have choices and I’m sure I can find circumstances where each approach will be beneficial.

Tags:

.Net | ASP.Net | Silverlight | WCF

Windows 7, Silverlight and the Unrecognized Element Exception

by mgordon 12. June 2009 04:22

I recently rebuilt my development laptop with Windows 7 and have been developing on it.  I have an existing Silverlight application that I have been deploying to a Windows Server 2003 machine and encountered some odd behavior after making modifications to in on the Windows 7 box and deploying it to the server.  The application ran fine on the development box, but after deploying to Windows 2003, any time the application made a call to a WCF service, an exception was raised declaring that an unrecognized element had been encountered.  After looking through several of the XML files in the solution, I happened upon the problem.

When looking at the ServiceReferences.ClientConfig file, I found the bindings defined there looked like this:

<binding name="BasicHttpBinding_Processing" maxBufferSize="2147483647"
    maxReceivedMessageSize="2147483647">
    <security>
        <transport>
            <extendedProtectionPolicy policyEnforcement="Never" />
        </transport>
    </security>
</binding>

The security element and everything within it was added when I modified one of the service references in my Silverlight project.  Removing all occurrences of these tags solves the problem.  These tags are not added under the same circumstances when developing on Vista or XP.

I’m still not sure why these tags were added.  I’m running .Net 3.5 SP1 on both my development machine and the server.

Tags:

.Net | ASP.Net | Silverlight | WCF

Accessing the Membership Provider from Silverlight

by mgordon 13. May 2009 04:50

In a particular Silverlight application, I felt it would be common for a user to have the application open for long periods, but not necessarily be interacting with it all the time.  This meant that there was always a chance the user’s session would time out.  Since the application uses the Membership and Role providers, nasty errors were being raised from web service calls depending on data from these providers if the session was not available.

To handle this situation, I tested for a valid session in my services and raised a custom exception if it wasn’t available.  Then, using the ideas in my last post I trapped that exception in my Silverlight application and showed a login box to the user so they could log back into the application and re-establish a valid session.

The next piece of this puzzle to solve was how to gain access to the Membership Provider from the Silverlight application to log the user back in.  Turns out there are two ways to go and both are equally valid for an Ajax application as well as Silverlight, though one is clearly more suitable for Ajax than Silverlight.

ASP.Net Ajax

The first solution is to use functionality built into the ASP.Net Ajax framework.  There is a javascript object in the framework, Sys.Services.AuthenticationService, that provides the needed functionality.  So, if you have all the necessary parts of the Ajax framework set up, in JavaScript you can say

var ssa = Sys.Services.AuthenticationService;

ssa.login(username,
              password,
              isPersistent,
              customInfo,
              redirectUrl,
              onLoginComplete,
              onError);

Of course you pass the username and password.  IsPersistent is a bool value indicating whether or not the user wants to be “remembered” by the application.  CustomInfo can be null as can the redirectUrl.  Of course, if you would like the user to be redirected to a certain Url after a successful log in, you’d specify that Url. The last two values are pointers to the methods to call when the login has completed or has errored out.  If you’re calling this from a web page it’s straight forward and from Silverlight, you’d need to wrap this code in a JavaScript function, and then call it from Silverlight like this.

Exposing Authentication as Web Service

Brad Abrams has an excellent tutorial on how to expose the needed functionality as a web service, here.  This was the approach I ended up using in my Silverlight application because it fit well with how the rest of the application was designed.   Once the functionality has been exposed as a web service, you could call this web service the same way you’d call any other from an Ajax application.

Tags:

.Net | Silverlight | WCF | ASP.Net

WCF Exceptions in Silverlight

by mgordon 6. May 2009 08:49

I’ve been working on a fairly substantial Silverlight 2 application and finally took on an aspect of it that I had been dreading and putting off for some time – exception handling – specifically handling exceptions being thrown from my WCF services.  I just knew this was going to be a bear.  Turns out, it wasn’t quite as bad as I had feared, but it was enough trouble that I thought a blog post sharing the experience would be a good thing.

The Problem

Silverlight doesn’t communicate directly with your web services, but rather it uses the browser API for this communication.  When calling a web service, if any exception occurs, the browser converts this into a generic 400 (Page not found) error and hands it back to Silverlight.  The result is that inside your Silverlight application, you know that an exception has occurred during your call, but have no way of knowing what it was.  This problem is supposed to be fixed in version 3.

The Research

This was certainly something I didn’t want to rush into solving so I did a bit of research on the Internet before jumping in.  Some we solving this by using out parameters on their services that contained the exception information which required checking the value of this parameter after each call.  I found a solution that was quite nice on CodeProject that used attributes on the service methods and contracts and a base class for the proxy on the client.  Since I’m still using Visual Studio generated proxies in my project, this one aspect of the solution made it unusable for my purposes.  In a discussion, here, I discovered that Microsoft’s Silverlight web service team had published a solution to the problem.  I checked it out and decided on this solution for my application.  A blog post about the solution can be found here and the code can be downloaded from code.msdn.microsoft.com.

The Code and Configuration

I found a few blog posts from folks who had implemented this solution, but none that were comprehensive and none that addressed its use with Visual Studio generated proxies.  Below, then, are the steps I took to get it all working in my application.

First, download the code the Silverlight web service team makes available and compile all the solutions.  You’ll need to set references to a few of the generated assemblies.

References

In the web project containing your WCF web services, set a reference to the assembly “SilverlightFaultBehavior.dll”.  Now, in your Silverlight project set references to the assemblies “SilverlightRawFaults.dll” and “SilverlightMessageInspector.dll”.

Code

If the web project containing your WCF web services doesn’t have a Global.asax file, add it and add the following code to it.  This code will cause any service requests that fail to return a 200 status code instead of 400.

 

protected void Application_EndRequest(object sender, EventArgs e)
{
    if (HttpContext.Current.Request.PhysicalPath.EndsWith(".svc", StringComparison.OrdinalIgnoreCase) &&
        HttpContext.Current.Response.StatusCode == 500 &&
        !HttpContext.Current.Request.Browser.Crawler &&
        HttpContext.Current.Request.Browser.EcmaScriptVersion.Major > 0)
    {
        // Set 200 if its a faulted service request
        HttpContext.Current.Response.StatusCode = 200;
    }
}
 

In any Silverlight class that makes a call to a WCF service, add the following (C#).

using Microsoft.Silverlight.Samples;
using SilverlightRawFaults;

At the point where you’re making the WCF call, you’ll be creating an instance of the proxy for that service.  Before making the call on that proxy, replace its binding by adding a line similar to this.

proxy.Endpoint.Binding = new BasicHttpMessageInspectorBinding(new SilverlightFaultMessageInspector());

This binding will ensure that the message inspector has a chance to look at the message returned from your call.

Finally, in the completed event for your service call, you’ll need to evaluate the Error property on the passed in event argument. 

if (e.Error != null && e.Error is RawFaultException)
{
    RawFaultException exception = (RawFaultException)e.Error;
    MessageBox.Show("Service says: " + exception.FaultMessage + Environment.NewLine +
        "Exception type: " + exception.FaultType + Environment.NewLine +
        "Stack trace: " + exception.StackTrace);
}
The Bug

After making the above modifications to my code, the value of the FaultMessage was not what I was expecting.  No matter what the exception was, this property always had the same generic value.  I found that there was a bug in the code provided by the Silverlight web service team and once it was corrected, all worked as expected.

Correcting the Bug

To correct the bug, open the downloaded solution called “SilverlightRawFaults”.  In the SilverlightRawFaults project, you’ll find a class called “BasicHttpMessageInspectorBinding”.  There is a property on this class called “FaultMessage” (oddly enough, the value that was incorrect).  Change this

public string FaultMessage 
{
    get { return Message; } 
}

to this

public string FaultMessage 
{
    get { return message; } 
}

Note that all I changed was the case of the “M” in “message”.  In this class, message is a member variable where Message is a property of the base class which is never set.  In the method RawFaultException sets message to the string containing the exception’s message, which is the value that should be returned.

Tags:

.Net | Silverlight | WCF

VisualTreeHelper Class in Silverlight

by mgordon 20. February 2009 08:37

It’s hard for me to believe I’d never encountered the situation before, but I was recently working on a part of a Silverlight application where I’d used a ListBox and specified an ItemTemplate within it containing a CheckBox and a TextBlock.  When a particular event fired, I wanted to iterate through all the ListBox Items, examine the Text property of the TextBlock and based on some simple logic, either check or uncheck the CheckBox.  My XAML for the ListBox looked like this:

<ListBox Margin="-5.057,34.225,0.116,0.121" Grid.Row="1" x:Name="lbRoles">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel HorizontalAlignment="Stretch" Orientation="Horizontal" >
                <CheckBox Checked="CheckBox_Checked"></CheckBox>
                <TextBlock Margin="5,0,0,0" Text="{Binding Path=RoleName}" FontWeight="Bold" 
Width="Auto" HorizontalAlignment="Stretch"
LineStackingStrategy="BlockLineHeight" LineHeight="15"/> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox>

So, basically, I was binding the ListBox to a collection and populating the TextBlock’s Text property from the binding.  My first task was to figure out how to access the ListBoxItem’s since The ListBox’s Items property would return the collection it was bound to and not the generated Items. I did some research and came across a newsgroup thread, here that contains an example of using the VisualTreeHelper class

In that thread, there is method defined like so:

private void GetChildren(UIElement parent, Type targetType, ref List<UIElement> children)
{
    int count = VisualTreeHelper.GetChildrenCount(parent);
    if (count > 0)
    {
        for (int i = 0; i < count; i++)
        {
            UIElement child = (UIElement)VisualTreeHelper.GetChild(parent, i);
            if (child.GetType() == targetType)
            {
                children.Add(child);
            }
            GetChildren(child, targetType, ref children);
        }
    }
}


You’ll notice that the method requires you to specify a type of control you’re interested in and also that it uses recursion to walk through every control in the visual tree beneath the specified parent.  I quickly found there is a vast hierarchy of controls created for the ListBox beyond what you’ll see in your XAML so it makes sense to recurse the tree of controls and only return what you’re needing.  I added this method to my class and used it for the above described problem like this:

List<UIElement> items = new List<UIElement>();
GetChildren(lbRoles, typeof(ListBoxItem), ref items);

foreach (ListBoxItem item in items)
{
    List<UIElement> children = new List<UIElement>();
    GetChildren(item, typeof(CheckBox), ref children);
    CheckBox cb = (CheckBox)children[0];

    children.Clear();
    GetChildren(item, typeof(TextBlock), ref children);
    TextBlock block = (TextBlock)children[0];

    if (_currentUserRoles.Contains(block.Text))
    {
        cb.IsChecked = true;
    }
    else
    {
        cb.IsChecked = false;
    }
}

So, using VisualTreeHelper and the helper method, I’m able to iterate through all the ListBoxItems and within each, to get a reference to the CheckBox and TextBlock within it.

Tags:

Silverlight | .Net

Powered by BlogEngine.NET 1.5.0.7
Theme by Extensive SEO