Logo Subtitle Subtitle

Unselecting a Silverlight combobox: How to unring the bell?

Download demo project: ComboboxUnselect 

Download action: ComboBoxUnselectAction.zip 

Before I start I’d like to tell you that in my humble opinion a combobox (or dropdown list) should contain values of the same kind. No value should mean something completely different than all the other items.
I also think a combobox should always have a default value selected. Like a checkbox should be checked or unchecked. Not gray-checked.  

Yeah yeah…


Fortunately no-one is waiting for my opinion :-) and the first item of a combobox is often used to offer a not-selected value to the user, like “<no selection>” or “Choose product”. Let’s call this the NULL-value.
To offer this value you can add the NULL value in the source list that feeds the combobox or write some behavior that adds the NULL value at position 0 in the combobox. Both methods work but can cause some unpredictable behavior. What is a null item in a list of employees? What is an empty comboboxItem in a combobox with employees?  

How would the user like to clear the combobox?

Today I needed to filter a list. I created a combobox and a grid and when I select a comboboxitem, the ItemSource of the grid is nicely filtered.
But to clear the filter I needed a way to unselect the combobox. And while it’s not hard to do this technically, I wondered what was the best way from a user’s point of view.
A quick google showed me a few popular methods:  

  • Link a checkbox to the combobox. If the checkbox is unchecked, the SelectedItem of the combobox is set to NULL and the combobox is grayed out.
  • Add a first dummy value like “<no selection>” at position 0 of the combobox.

The first method needs 3 clicks: Check checkbox, Click combobox arrow down, Click item.
The second method has that tricky unpredictable first item.
I know that I can inspect my list with reflection and see what kind of list it is and add an item of the same type but I got tired even thinking of needing so much code.
And I don’t want to give meaning to a -1 or 0 selectedIndex.  

My luck was that I’m working with Silverlight/MVVM. Due to the many failures I make, I often noticed that a Combobox.SelectedItem=null results in a nice blank combobox.
So let’s use that! I wrote a demo project that has a list of employees wich populate a combobox. I put a button on the page and dropped a ComboBoxUnselectAction on it.  

You can see it here in action:

Install Microsoft Silverlight

  The ComboBoxUnselectAction has a dependency property to target the Combobox:  

[CustomPropertyValueEditor(CustomPropertyValueEditor.ElementBinding)]
public ComboBox TargetComboBox
{
    get { return (ComboBox)GetValue(TargetComboBoxProperty); }
    set { SetValue(TargetComboBoxProperty, value); }
}

public static readonly DependencyProperty TargetComboBoxProperty =
    DependencyProperty.Register("TargetComboBox",
                                typeof(ComboBox),
                                typeof(ComboBoxUnselectAction),
                                new PropertyMetadata(null, OnTargetComboBoxPropertyChanged));

private static void OnTargetComboBoxPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var source = d as ComboBoxUnselectAction;
    if (source != null)
    {
        var value = (ComboBox)e.NewValue;
    }
}

And an implementation of the Invoke method:

protected override void Invoke(object o)
{
    if (this.TargetComboBox != null)
        this.TargetComboBox.SelectedItem = null;
}

NullableCombobox usercontrol

If you want to take it one step beyond you can create a usercontrol that holds the combobox and NULL-button. You could even show a “Choose artist” label on top of the combobox if the SelectedItem==null. But if the ComboBoxUnselectAction is just what you are looking for, just download ComboBoxUnselectAction.zip

Windows Phone 7 at Atos Origin

Download Presentation: WindowsPhoneSampleData

Yesterday I demonstrated how to create a Windows Phone 7 application with Expression Blend at the Atos Origin Microsoft Unit where I worked until 2004. There were some great discussions about the relation between iPhone, Android, Windows Phone, HTML5 and Silverlight. After finishing the demo someone asked how to deploy the demo to a real phone.

LG Windows Phone

I brought my friend and co-worker Fons Sonnemans to the meeting. Fons is one of the lucky guys in the Netherlands who has a real LG Windows Phone. (Courtesy Matthijs Hoekstra at Microsoft). We deployed the demo to the phone and people could actually use it on the phone.


me and the phone.

I would like to thank Rob Hodzelmans and the rest of my old colleagues for a great evening!

Committing a datagrid row (EndEdit) in a viewmodel

By allowing users to edit data in a Silverlight DataGrid, you have to make sure the datarows are properly committed before submitting to the database.
In an MVVM situation I bind the DataGrid to:

public ObservableCollection<Uur> Uren { get; set; }

I save data with the following SaveCommand:

SaveAllCommand = new DelegateCommand<object>(o =>{    Context.SubmitChanges();});

If a datagrid row is this in Edit-mode, this error could occur:
Entity is currently being edited and has uncommitted changes.
A call to BeginEdit must be followed by a call to EndEdit or CancelEdit before changes can be submitted.

Solution

Before submitting, commit all entities:

SaveAllCommand = new DelegateCommand<object>(o =>{
  Uren.ToList().ForEach(uur => (uur as IEditableObject).EndEdit());
  Context.SubmitChanges();
});

The specified type member Date is not supported in LINQ to Entities

On a RIA-enabled Silverlight project I wrote the following LINQ to Entities query in my Domain Service:

public IQueryable<Order> GetOrders()
{
  var qry = from order in ObjectContext.orders
            where order.OrderDate.Date == DateTime.Now.Date
            select order;
            return qry;
}

I want to ignore the time part of the DateTime so I only compare the date parts but when I ran the query I got this error:
Load operation failed for query 'GetOrders'. The specified type member 'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.

Solution Part 1 (Works in a viewmodel)

I’ve had this error before and remember I had to check if my date was between a start and end date. Like this:

var qry = from order in ObjectContext.orders
    where order.OrderDate >= DateTime.Now.Date
    && order.OrderDate < DateTime.Now.Date.AddDays(1)
    select order;
    return qry;

But while this works if you build this query on the client (like in a viewmodel), it fails when it’s constructed in a DomainService with the following error:
Load operation failed for query 'GetOrders'. LINQ to Entities does not recognize the method 'System.DateTime AddDays(Double)' method, and this method cannot be translated into a store expression.

Solution Part 2 (Works in DomainService)

Well, the answer is easy enough but not too elegant. We need a helper variable where you add a day to the datetime:

var date2 = DateTime.Now.Date.AddDays(1);
var qry = from order in ObjectContext.orders
             where order.OrderDate >= DateTime.Now.Date
             && order.OrderDate < date2
             select order;
             return qry;