Bindable LINQ: Silverlight
Update: SyncLINQ has been released under the name Bindable LINQ, and is available from CodePlex
My last couple of posts have hinted at it, but now it’s finally here: SyncLINQ running within Silverlight 2.0 beta 1. If you have it installed, you should see the application below:
Go ahead, try it out:
- Type in the filter
- Add an item that passes your filter - it should appear, and should be in the correct order
- Add an item that doesn’t pass your filter - it won’t appear
Now you’re wondering: how much code did it take to write that?
Here’s the class representing a Contact - a plain old .NET class:
public class Contact : INotifyPropertyChanged
{
private string _name;
private string _company;
private string _phoneNumber;
public Contact()
{
}
public string Name
{
get { return _name ?? ""; }
set
{
_name = value;
this.OnPropertyChanged(new PropertyChangedEventArgs("Name"));
}
}
public string PhoneNumber
{
get { return _phoneNumber ?? ""; }
set
{
_phoneNumber = value;
this.OnPropertyChanged(new PropertyChangedEventArgs("PhoneNumber"));
}
}
public string Company
{
get { return _company ?? ""; }
set
{
_company = value;
this.OnPropertyChanged(new PropertyChangedEventArgs("Company"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
handler(this, e);
}
}
}
And here’s the code-behind for the Silverlight Page:
public partial class Page : UserControl
{
private ObservableCollection<Contact> _contacts;
public Page()
{
InitializeComponent();
_contacts = new ObservableCollection<Contact>();
_contacts.Add(new Contact() {Name = "Paul Stovell", Company = "Readify", PhoneNumber = "0421 938 793"});
_contacts.Add(new Contact() {Name = "Omar Besiso", Company = "Readify", PhoneNumber = "0421 938 793"});
_contacts.Add(new Contact() {Name = "Darren Neimke", Company = "Readify", PhoneNumber = "0421 938 793"});
_contacts.Add(new Contact() {Name = "Mitch Denny", Company = "Readify", PhoneNumber = "0421 938 793"});
_contacts.Add(new Contact() {Name = "Richard Banks", Company = "Readify", PhoneNumber = "0421 938 793"});
_contacts.Add(new Contact() {Name = "Andrew Matthews", Company = "Readify", PhoneNumber = "0421 938 793"});
_contactsList.ItemsSource = _contacts.AsBindable()
.Where(c => c.Name.ToLower().StartsWith(this.FilterTextBox.Text.ToLower()))
.OrderBy(c => c.Name.ToLower());
_newItemPanel.DataContext = new Contact();
}
public TextBox FilterTextBox
{
get { return _filterTextBox; }
}
private void SaveButton_Click(object sender, RoutedEventArgs e)
{
Contact contact = (Contact)_newItemPanel.DataContext;
_contacts.Add(contact);
_newItemPanel.DataContext = new Contact();
}
}
The public property exposing the FilterTextBox is a workaround because you can’t invoke private members via reflection in Silverlight. I would have used x:FieldModifier on the element, but that doesn’t seem supported by Silverlight yet (the .g.cs generator respects it, but Silverlight borks at runtime when it encountered the attribute).
Apart from some temporary compatibilities and missing features, overall I’m really happy about the Silverlight developer story. I will post some more thoughts on this later. For now, goodbye JavaScript!
Note: the background image in the Silverlight application is a photo by Bill McCarthy. Bill has lots of nice photos, and I hope he doesn’t mind me using this one in a sample
Filed under: Bindable LINQ


Great work! I can’t wait to start playing with this.
BTW, the backspace does not work in the filter text box. Is that a silverlight issue or something to do with your framework?
Paul,
Very nice work sir!
I hope to publish my Silverlight database application this week before the MVP Summit.
Thanks for sharing with the world!
Cheers,
Karl
Hi Paul,
I notice your sample Contact class raises PropertyChanged events regardless of whether the value actually changes. Is the a simplification for the purpose of this post or do you find it is necessary for reliable binding.
One of the many aspects of DataSets that annoy me is that they similarly fire ColumnChanged events even if the data is the same and it can cause issues.
Regards,
@Rob - backspace - works here, can anyone else confirm? I’m guessing it’s a framework thing.
@Jason - two reasons really. First, laziness - it’s a whole extra line to check the value first
Second, habit from dealing with WPF validation and converters on an application I built. Sometimes if you have a converter, the user could enter the same kind of data many different times (i.e., typing a string into a TextBox that was trying to convert to an int). The converter might normalize that data (return 0), but since the 0 value was the same, validation wouldn’t fire since PropertyChanged wasn’t raised. Probably more an issue with the validation lib I was using 
I’m not too worried about checking the value of a property before raising the PropertyChanged event. In fact, I’ve made use of the fact that it doesn’t care in the past. Forcibly refreshing something by setting a property to itself, sort of thing.
Love your demo app there, Paul. Admittedly it’s only a handful of rows, but it’s nice and snappy!
Paul,
Backspace works great for me.
Using Vista x64, IE 7.
Karl
Backspace works for me too.
Using XP (32 bit), IE7
@Paul: that’s cool and all, however a real POCO would not need to have the PropertyChanged thing hand coded into it.
[…] SyncLINQ for Silverlight (Paul Stovell) […]
Backspace works fine here, too.
Rob must have a bum keyboard.
–rj
Awesome.
@Ken,
That’s true, but there must be a way for the object to signal that a property has been changed. In this example, we actually wouldn’t have had to implement INotifyPropertyChanged. INPC is useful in many other contexts other than data binding too. And since it’s existed since .NET 1.0, and it’s in System.ComponentModel, I see no reason why every object in .NET shouldn’t implement it.
[…] Any and all of the usual tricks for LINQ apply to SQLCE - once you generate the dbml via SQLMetal, it really doesn't care what is underneath. If you want to bind it properly to WPF with automagic updates for when the datasource updates, I strongly recommend looking into the very clever SyncLINQ by the equally clever Paul Stovell, which also supports Silverlight. […]