Wednesday, March 18, 2009

Adventures while building a Silverlight Enterprise application part #9

Well, here we are again, already for part #9 of our series on using Silverlight in an Enterprise application. Last time we looked at some of the tricky bits on using Entity Framework in our application.


This time we want to look at a particular databinding technique, that we tend to use a lot on forms in our application. We want to look at lookup data and using classes in lookup data. What I mean is using a combobox to select some object from a list that describes part of our own data.

Below is an image of what I'm trying to do here:



As you can see we have a datagrid with computers. Whenever I select a record from the grid, this record is displayed in the form. But the casing combobox will not show me what item is selected, although I did databind to the SelectedItem property and they are the same type. The problem is that they are not the same instance.

Now if I would replace the Casing type with string and fill the combobox with a list of strings, all would work fine. This actually gives away a simple but important fact about how matching is done to select the item in the combobox. It uses some sort of comparison. So let's implement the most obvious form of comparison to make sure that equal casings actually say that they are equal, by overriding the Equals method.

public class Casing
{
public string Name { get; set; }

public override bool Equals(object obj)
{
Casing casing = obj as Casing;
if (casing != null)
{
return casing.Name.Equals(Name, StringComparison.OrdinalIgnoreCase);
}
return false;
}

public override int GetHashCode()
{
return Name.GetHashCode();
}
}

As you can see I've also overridden GetHashCode. As Visual Studio will indicate, it's best practice to always override both of the methods at the same time, so sorting follows the same logic as the Equals method. As we use the Name property to evaluate if two casings are the same, it's only logical to also use the Name properties hashcode.


Now if you look at the application, it looks like this:


Mission successful. Conclusion: if you want to be able to use lookups, always override the Equals method on your business objects.

You can download this example project below:


I hope this article was helpful for you and I look forward to reading your comments and answering any questions.

7 comments:

  1. Thank you.

    Question: I'm using a template to display the 'displaymember' that uses a converter

    ie.

    Laptop Model 123

    The converter taking 2 fields and combining them.

    What would I use for my Equals? Any unique item of Casing? (ie. a Casing Id)

    ReplyDelete
  2. Hi SteveG,

    Good question, thanks.
    Yes, using an id to compare objects is completely valid. The goal is to make sure that equal objects in diferent instances still evaluate as being equal.

    This is not default behaviour because objects normally are compared based on where the pointer for that object points in memory (different instances mean different objects).

    Another aproach could be to have more then one property that makes for a unique object. In that case, having an equals method to first combine these properties before a compare can be a valid solution, but that realy depends on specifics for the application. Having an id is always the safest way to go.

    Does that answer your question?

    Greets,
    Jonathan

    ReplyDelete
  3. jonathan,

    You're using an OrdinalIgnoreCase comparison in your Equals method, while simply returning the string's normal hash code in GetHashCode so the two methods are not consistent with each other.

    For instance, Equals will return true for "LaptoP" and "laPTop" but GetHashCode will return different values for them.

    ReplyDelete
  4. Hi vlad,

    You're absolutely right, they are inconsistent. My example application is not the ideal scenario, as I would not want this to be based on strings anyway. As discussed earlier, you would want to use a unique identifier to compare on.

    But I get your point. Always use consistent logic in Equals and GetHashCode.

    Greets,
    Jonathan

    ReplyDelete
  5. The method you describe worked terrific for me. I had been struggling with getting the SelectedItem property to work on my Silverlight ComboBoxes. Thanks so much for this post!

    ReplyDelete
  6. You're welcome, off the back. It's always good to know you've helped someone with a good blog post.

    ReplyDelete
  7. When you need to get things done, sometimes a hammer is still the best tool.

    ReplyDelete