Feb 072011
 

In WPF data binding is fairly consistent, I would even dare to say best that I ever saw. It is easy to do fairly complex things at some cost to way how simpler things are done. Internet is full of examples how to do simple WPF data binding but it surprisingly lacks examples for doing background updates. I tried here to make simplest example that will work with dynamic updates.

Everything revolves around ObservableCollection. In my example this class is inherited within ItemViewCollection class and all “filling” should be done to Items property. I opted to do so with hard-coded data but you can imagine it being done with data from database or any other source.

...
this.Items.Clear();
this.Items.Add(new ItemViewData("Primary weapons", 1000));
this.Items.Add(new ItemViewData("Secondary weapons", 1000));
this.Items.Add(new ItemViewData("Shields", 1000));
this.Items.Add(new ItemViewData("Torpedos", 1000));
this.Items.Add(new ItemViewData("Item " + DateTime.Now.ToLongTimeString(), 1000));
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
...

Once data is shown, it will not be refreshed unless OnCollectionChanged method gets called. Only then update will propagate around. Above we can see how whole collection should be refreshed once Items get cleared and filled again. If you see that ListView does not respond to your changes (e.g. you added some items) there is chance you forgot to call it.

Data itself is stored within ItemViewData class. That class implements INotifyPropertyChanged interface and thus it enables update notifications for selected properties (e.g. Energy and ImageIndex). You could update all properties but updating only those that you actually changed will improve performance. Again, if you changed property and your ListView does not reflect it, you forgot to do notification.

public void SetEnergy(decimal newEnergy) {
    if (newEnergy < this.Energy) {
        this.ImageIndex = 1; //down
    } else if (newEnergy > this.Energy) {
        this.ImageIndex = 2; //up
    } else {
        this.ImageIndex = 0; //same
    }
    this.Energy = newEnergy;
    this.OnPropertyChanged(new PropertyChangedEventArgs("Energy"));
    this.OnPropertyChanged(new PropertyChangedEventArgs("ImageIndex"));
}

Code that handles data binding is in following (abreviated) XAML:
[xml]

<Window.Resources>
<ObjectDataProvider x:Key="parts" ObjectType="{x:Type local:ItemViewCollection}" MethodName="GetInstance" />
</Window.Resources>

<ListView Name="List" ItemsSource="{Binding}" DataContext="{Binding Source={StaticResource parts}}">

</ListView>

[/xml]

What really happens here?

ListView uses binding to “parts” data provider in order to call GetInstance method within item collection (ItemViewCollection). Whatever this method returns get’s treated as rows for ListView control. Our code is responsible for putting right stuff inside (in FillItems method) and for doing it in correct thread (thus Invoke code there). This is all there is to it.

To make things more interesting I added small method (BackUpdate within App.xaml.cs) that updates some values every two seconds (INotifyPropertyChanged.OnPropertyChanged gets triggered here) and every 20 seconds everything gets reloaded from start (thus need for ObservableCollection.OnCollectionChanged).

It might seem complicated when you look at it for first time but once you see full example code these code fragments should make some sense. :)

  3 Responses to “How hard can it be to create ListView”

Comments (3)
  1. nice article, i will play with the code
    thanks man :)

  2. by the way, how to convert png to xaml?

    • There is no satisfactory route for .png (raster) to .xaml (vector) conversion. You need to get xaml images for best effect (or, if you like blurriness, you can use .png directly).

 Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>