tags:

views:

664

answers:

3

Ok, this has been a head scratcher for me. I have a ListBox I am binding to a linq query like so:

    private IQueryable<Feed> _feeds;

    public IQueryable<Feed> Feeds
    {
        get
        {
            if (_feeds == null)
            {
                var feedsQuery = from f in _db.Feed orderby f.Title select f;
                _feeds = feedsQuery;
            }
            return _feeds;
        }
    }

    public Options()
    {
        InitializeComponent();
        this.DataContext = Feeds;
    }

(For the record I've also tried List, instead of IQueryable)

Everything shows up great and I have a databound form that allows you to edit a record and all of those changes work just fine, the modified data shows up in the list.

The problem comes with I add an item. Nothing shows up in the list. The data goes into the database fine, but the only way to see the data is closing and restarting my app. I'm using the code below as an example:

        Feed feed = new Feed()
        {
            ID = Guid.NewGuid(),
            Url = "http://www.test.com",
            Title = "Test"
        };
        _db.Feed.InsertOnSubmit(feed);
        _db.SubmitChanges();
        _db.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues);

(with or without the _db.Refresh nothing happens)

What's going on?

+2  A: 

You are doing everything right, you jus need to use ObservableCollection. This will notify the ListBox about any changes in the list and refresh it automatically.

From MSDN

In many cases the data that you work with is a collection of objects. For example, a common scenario in data binding is to use an ItemsControl such as a ListBox, ListView, or TreeView to display a collection of records.

P.S. you don't need a db refresh

Stan R.
Using an ObservableCollection won't be enough to solve the problem, the query needs to be run against the database again
Thomas Levesque
+1  A: 

Unless notified otherwise, the ListBox only iterates once over its ItemsSource. Your query is only being run once.

The query object doesn't know when the database changes (and Refresh doesn't help; see below)--it's up to you to know (or anticipate) that and to rerun relevant queries at the appropriate times.

Stan R mentions ObservableCollection. That's fine, but simply storing the result of your query in an ObservableCollection won't solve the problem unless you do some work to update the collection yourself when the database changes. This means rerunning the query and manually adding new items and removing deleted items from the collection. (You could alternatively just rerun the query and set the entire result back in to the ListBox, but that means a whole new set of items will be created--not very performant, and maybe not what you want for other reasons.)

As an aside, your call to DataContext.Refresh is probably not doing what you think it is. From the docs:

This method is useful after an optimistic concurrency error to bring items into a state for another attempt. It updates the state of the primitive fields and properties on the objects.

Ben M
A: 

Okay. I'm not positive this is 100% the correct way to use the ObservableCollection, but this seems to work:

 private ObservableCollection<Feed> _feeds;
        public ObservableCollection<Feed> Feeds
        {
            get
            {
                if (_feeds == null)
                {
                    var feedsQuery = from f in _db.Feed orderby f.Title select f;
                    _feeds = new ObservableCollection<Feed>();
                    foreach (var item in feedsQuery)
                    {
                        _feeds.Add(item);
                    }
                }
                return _feeds;
            }
        }

And add my item:

Feed feed = new Feed()
            {
                ID = Guid.NewGuid(),
                Url = "http://www.test.com",
                Title = "Test"
            };
            _db.Feed.InsertOnSubmit(feed);
            _db.SubmitChanges();
            // manually update the list
            Feeds.Add(feed);

It took me a little while to figure out I had to update the list manually (thanks Ben), but it all seems to work. Sorting would be nice, but I'll worry about that another time.

cadmium