tags:

views:

681

answers:

3

I've got a view which shows a listbox that is bound to GetAll():

<DockPanel>
    <ListBox ItemsSource="{Binding GetAll}"
             ItemTemplate="{StaticResource allCustomersDataTemplate}"
             Style="{StaticResource allCustomersListBox}">
    </ListBox>
</DockPanel>

GetAll() is an ObservableCollection property in my ViewModel:

public ObservableCollection<Customer> GetAll
{
    get
    {
        return Customer.GetAll();
    }
}

which in turn calls a GetAll() model method which reads an XML file to fill the ObservableCollection.:

public static ObservableCollection<Customer> GetAll()
{
    ObservableCollection<Customer> customers = new ObservableCollection<Customer>();

    XDocument xmlDoc = XDocument.Load(Customer.GetXmlFilePathAndFileName());
    var customerObjects = from customer in xmlDoc.Descendants("customer")
                          select new Customer
                          {
                              Id = (int)customer.Element("id"),
                              FirstName = customer.Element("firstName").Value,
                              LastName = customer.Element("lastName").Value,
                              Age = (int)customer.Element("age")
                          };
    foreach (var customerObject in customerObjects)
    {
        Customer customer = new Customer();

        customer.Id = customerObject.Id;
        customer.FirstName = customerObject.FirstName;
        customer.LastName = customerObject.LastName;
        customer.Age = customerObject.Age;

        customers.Add(customer);
    }

    return customers;
}

This all works fine EXCEPT when the user goes to another view, edits the XML file and comes back to this view where the old data is still showing.

How can I tell this view to "refresh its bindings" so that it shows the actual data.

It feels like I am going about WPF here with too much of an HTML/HTTP metaphor, I sense there is a more natural way to get ObservableCollection to update itself, hence its name, but this is the only way I can get the user to be able to edit data in a WPF application at the moment. So help on any level is appreciated here.

A: 

I'm no expert but it looks like you're going about it the wrong way.

I don't think an observable collection observes static methods. ex: Customer.GetAll();

Maybe if you changed it to a property?

vidalsasoon
A: 

Keep a reference to your ObservableCollection and the XML file's last-modified time as of the time you loaded it. Whenever the window gets focus, check the timestamp on the disk file. If it's changed, clear and re-populate the ObservableCollection. The GUI is automatically listening for change events from the ObservableCollection and will re-populate automatically when you modify the collection's contents.

Joe White
+1  A: 

An ItemsControl requests its binding once and caches the reference thereafter.

If the content of the collection object are modified, and it implements INotifyCollectionChanged (as ObservableCollection does), it will pick up any added or removed object.

Now, if you want the binding to supply a new collection object to the ListBox, you can have your viewmodel implment INotifyPropertyChanged and raise PropertyChanged, passing in "GetAll" as the property name. This will have the effect of warning the binding that the property value has changed (there is a new ObservableCollection ready to be picked up), which it will supply to the Listbox, which will re-generate its items.

So as long as you effect changes from your app, working on the observablecollection returned by GetAll, you can add and remove and the list will stay in synch. When you want to pick up external modifications (you might have a refresh button somewhere, or a natural point where it makes sense to reload the whole file), you can have your ViewModel raise the PropertyChanged event, which will automatically call the property getter, which will call the static method, which will return a fresh new collection.

Nitpicker note: why do you give method names to properties?

Denis Troller
I changed GetAll() to GetAll, thanks. The problem is that I have two views which each get a separate GetAll ObservableCollection from their respective ViewModels and when one ObservableCollection changes, the other one doesn't change. Do I need to store these globally somewhere?
Edward Tanguay
If both views are supposed to be synchronized during edition, then yes, you need to somehow share the same object. In your case, there could be a Data Access system that loads and caches the collection, and each ViewModel would then request the current collection. That way they both are aware of each other's modification.Now if you need to reload the collection from the file, you would have a way to warn every viewmodel that the collection object has changed, so that they can raise their PropertyChanged event once they have obtained the new reference.
Denis Troller
So for now my solution as to refresh the DataSource every time the user control (view) is loaded, works great, thanks!
Edward Tanguay