For a new project at work, we are using WPF and Linq to Sql. In some ways data binding in WPF is very sexy and suave. In other ways, it's aggravating - there are things that are so easily done in WinForms and ASP .Net, like, say, re-binding data to a control after it's changed, that are bitch to figure out in WPF. At least for me they are.
In theory, WPF can update itself whenever the source changes. In reality, it's not quite as simple as it sounds.
First of all, if you happen to be extending the generic
ObservableCollection and have a method in your new class that adds items to the collection, using the Add() method
will update the control while using Items.Add()
will not update the control. Why? Who knows?
public class ObservableStringCollection : ObservableCollection
{
public ObservableStringCollection()
{
Add("First");
Add("Middle");
Add("Last");
}
public void AddMe(string s)
{
Add(s); //I notify controls I'm bound to!
Items.Add(s); //I don't notify!
}
}
Secondly, Linq to Sql is not observable so anytime you
SubmitChanges(), any control bound to your Linq classes doesn't get updated. I got around this by re-setting the
ItemsSource property. Ok, fine. Here's the strange part: using
ToArray() on the Linq collection
will set the source correctly, while using
AsEnumerable() will not set the source correctly.
AsEnumerable() will set the source correctly the first time it's bound.
tvPages.ItemsSource = CMSUtility.DataContext.CMS_Pages.ToArray(); // I work!
tvPages.ItemsSource = CMSUtility.DataContext.CMS_Pages.AsEnumerable(); // I only work the first time!
Currently, I'm working on extending the Linq DataContext to be somewhat observable.
I wrapped the Linq DataContext class and implemented the INotifyPropertyChanged interface. Then I overrode the SubmitChanges method to fire the notification event.
public class ObservableDataContext : LinqClassesDataContext, INotifyPropertyChanged
{
public ObservableDataContext() : base("Data Source=.;Initial Catalog=DB;Integrated Security=True") { }
public ObservableDataContext(LinqClassesDataContext dc) : base(dc.Connection, dc.Mapping.MappingSource) { }
public override void SubmitChanges(System.Data.Linq.ConflictMode failureMode)
{
base.SubmitChanges(failureMode);
NotifyPropertyChanged("Nodes");
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
#endregion
}
}
This way I can attach an event to the PropertyChanged for classes that I bind with.
That's the theory anyway. In practice, it's *
sort of* working - I am able to get the Linq SubmitChanges to notify my source object and rebind to my control. However, when it binds to the control again, it doesn't use my DataTemplates. That's for another post I guess.
I'm off to yoga ...