Display Live Data In Silverlight Using ObservableCollection and INotifyPropertyChanged
Download Source Code | Run Sample
Articles shows how to use ObservableCollection in combination with an object implementing INotifyPropertyChanged interface to display live data in Silverlight Application.
ObservableCollection is a generic dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed and INotifyPropertyChanged provides PropertyChanged notification to clients when any property value gets changed.
Sample Application in Nutshell
We are going to create a simple Silverlight Application which show DataGrid with user names and their respective scores, we will also create a simple Column Chart to display same user data. We will set ItemSource of both control to the same instance of ObservableCollection and finally we will create timer which will randomly update ObservableCollection by adding new row or updating score for random users.
User Class.
As you can see User Class implements INotifyPropertyChange interface, INotifyPropertyChange defines PropertyChanged Event which notifies subscriber on any change in properties, This is very important if you do not implement INotifyPropertyChange interface then any change in your property will not trigger updates in either datagrid and chart.
private string name ;
public string Name{
get { return name ; }
set {
if ( value ! = name){
name = value;
onPropertyChanged( this , "Name" ) ;
}
}
}
private long score ;
public long Score{
get { return score ; }
set {
if (score ! = value ) {
score = value;
onPropertyChanged( this , "Score" ) ;
}
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged ;
private void onPropertyChanged( object sender
, string propertyName){
if ( this .PropertyChanged ! = null ){
PropertyChanged(sender,
new PropertyChangedEventArgs(propertyName)) ;
}
}
#endregion
}
Observable Collection of User
As I mentioned earlier ObservableCollection implements INotifyCollectionChanged interface which defines CollectionChanged event which notifies subscribers on any change in collection, Unless you use ObservableCollection or custom class which implements INotifyCollectionChanged, updates that you make in collection will not trigger update in either datagrid or chart.
{
ObservableCollection<User> rVal = new ObservableCollection<User>() ;
rVal.Add( new User { Name = "Tom" , Score = 2 }) ;
rVal.Add( new User { Name = "Sam" , Score = 3 }) ;
rVal.Add( new User { Name = "John" , Score = 4 }) ;
rVal.Add( new User { Name = "Dave" , Score = 5 }) ;
rVal.Add( new User { Name = "Sue" , Score = 1 }) ;
return rVal ;
}
XAML Layout and Databinding.
We have a very simple XAML layout which includes DataGrid in top and Charting Control in bottom, Charting control has one ColumnSeries without any data.
< Grid.RowDefinitions >
< RowDefinition Height ="*" />
< RowDefinition Height ="300" />
</ Grid.RowDefinitions >
< data:DataGrid x:Name ="dataGrid" Grid.Row ="0" >
</ data:DataGrid >
< charting:Chart x:Name ="chartControl" Grid.Row ="1" Title ="Live Chart">
< charting:Chart.Series >
< charting:ColumnSeries DependentValueBinding ="{Binding Score}"
IndependentValueBinding ="{Binding Name}" />
</ charting:Chart.Series >
</ charting:Chart >
</ Grid >
We will use constructor to bind our data to datagrid and chart, we are also creating a timer which starts after 10 seconds and ticks every 2 second, we are going to randomly change data and add or remove row in collection whenever timer event fires.
Timer timer ;
public Page() {
InitializeComponent() ;
users = getUserCollection() ;
this .dataGrid.ItemsSource = users ;
((DynamicSingleSeriesWithAxes) this .chartControl.Series[ 0 ]).ItemsSource = users ;
timer = new Timer(timerFired, null , 10000 , 5000 ) ;
}
Updating Data
Very important thing to note here is the way in which we have to make updates to our datasource when we are not in UI thread, if you are familiar with Winforms development then you should be familiar with cross-thread access exception when you try to update UI element from another thread. Similar to windows development you will have to use BeginInvoke to make any updates to UI Element or In our case object which can trigger change in UI Element.
this .Dispatcher.BeginInvoke( delegate (){
Random rnd = new Random() ;
users[rnd.Next( 0 ,users.Count)].Score = rnd.Next( 1 , 5 ) ;
if (rnd.Next( 1 , 5 ) > 3 ) {
if (users.Count > 4 ){
users.RemoveAt( 4 ) ;
} else {
users.Add( new User { Name = "Sue" , Score = 1 }) ;
}
}
}) ;
}
We are randomly selecting a row in collection and updating its score, along with that we are also randomly adding or removing row from the collection. Although we are not rebinding our data with DataGrid or Chart they both with immediately get updated whenever source changes.
Closing Notes
You also get two way binding with INotifyPropertyChanged and DataGrid without adding single line of additional code, if you update Score or Name in DataGrid change will immediately trigger in change Chart Control.