0

Created a Windows Store App using some info found on this post: How do I use the Bing Search API in Windows Phone?

Goal

Textbox - Type any term Search Button - Searches that term and populates a GridView of pictures retrieved with the Bing API

Problem

I get the pictures, and they are received via my "OnQueryComplete" callback, but I can't figure out what the correct way to populate the collection would be. Since I can't figure out how to await this call, I (just to see if I could get it working, which it does) added a while loop (which you can probably see the issues with). What would be the correct way to do this? How do you handle callbacks for populating the GridView and having it wait until it's finished?

Current ViewModel Code

    public bool itemsFinished = false;
    private ObservableCollection<SearchResult> _ImageResults;
    public ObservableCollection<SearchResult> ImageResults {
        get {
            if (_ImageResults == null) {
                while (!itemsFinished) {
                    int i = 0;
                    i++;
                }
            }
            return _ImageResults;
        }
        set {
            _ImageResults = value;
        }
    }

    public SearchResultViewModel() {
       GetPictures("dogs");
    }


    public void GetPictures(string searchTerm) {
        // This is the query - or you could get it from args. 
        string query = searchTerm;
        // Create a Bing container. 
        string rootUri = "https://api.datamarket.azure.com/Bing/Search";
        var bingContainer = new Bing.BingSearchContainer(new Uri(rootUri));
        // Replace this value with your account key. 
        var accountKey = "myaccountkey";
        // Configure bingContainer to use your credentials. 
        bingContainer.Credentials = new NetworkCredential(accountKey, accountKey);
        // Build the query. 
        var imageQuery = bingContainer.Image(query, null, null, null, null, null, null);
        imageQuery.BeginExecute(OnQueryComplete, imageQuery);

        // var imageResults = imageQuery.Execute(); 
    }

    private void OnQueryComplete(IAsyncResult result) {
       // ImageResults.Clear();
        _ImageResults = new ObservableCollection<SearchResult>();
        var query = (DataServiceQuery<ImageResult>)result.AsyncState;
        var enumerableResults = query.EndExecute(result);
        int i = 0;
        foreach (var item in enumerableResults) {
            SearchResult myResult = new SearchResult();
            myResult.Title = item.Title;
            myResult.ImageUri = new Uri(item.MediaUrl);
            ImageResults.Add(myResult);
            i++;
            if (i >= 14) {
                break;
            }
        }
        itemsFinished = true;

    }
Community
  • 1
  • 1
Levi Fuller
  • 13,631
  • 4
  • 38
  • 44
  • Just a suggestion, but you might also want to ask for some tips on [CodeReview](http://codereview.stackexchange.com/) because there are indeed some issues with your code :) – Benjamin Diele Nov 21 '14 at 06:37
  • It's a rough Proof of concept I was doing to learn how to use the Bing API. I was trying anything to await the callback. – Levi Fuller Nov 21 '14 at 06:50

1 Answers1

0

Please excuse any syntax errors, I'm without a Visual Studio instance right now.

The problem I see is that you reset your ObservableCollection when you receive content.

Try it as follows:

private ObservableCollection<SearchResult> _ImageResults;
public ObservableCollection<SearchResult> ImageResults {
    get
    {
        return _ImageResults;
    }
    set {
        _ImageResults = value;
    }
}

public SearchResultViewModel() {
   _ImageResults = new ObservableCollection<SearchResult>(); // Just create it once.
   GetPictures("dogs");
}

private void OnQueryComplete(IAsyncResult result) {
    _ImageResults.Clear(); // Clear isn't bad, that way you keep your reference to your original collection!
    //_ImageResults = new ObservableCollection<SearchResult>(); // We already have one. ObservableCollection works best if you keep on working with the collection you have.
    var query = (DataServiceQuery<ImageResult>)result.AsyncState;
    var enumerableResults = query.EndExecute(result);
    int i = 0;
    foreach (var item in enumerableResults) {
        SearchResult myResult = new SearchResult();
        myResult.Title = item.Title;
        myResult.ImageUri = new Uri(item.MediaUrl);
        ImageResults.Add(myResult);
        i++;
        if (i >= 14) {
            break;
        }
    }
}

As far as I see (can't test sadly) this should work, provided you have bound your ObservableCollection the right way in your xaml.

Benjamin Diele
  • 1,177
  • 1
  • 10
  • 26
  • The problem is that when I try to implement it that way, it doesn't give the callback enough time to complete. My collection doesn't get populated because the callback event hasn't occurred (it takes a second to get the JSON from the API). Thus, "GetPictures" has finished, it's not awaited, so the collection of SearchResults isn't populated and the front end thinks it's done. I implemented the While loop, because it paused the getter until the collection was populated. Any idea how I could achieve something like that? – Levi Fuller Nov 21 '14 at 06:49
  • That should be solved by using an `ObservableCollection`. Every time you add / remove **items** to / from your collection, it sends an update to whoever has subscribed to the notifications of it (your ListView does that of its own). – Benjamin Diele Nov 21 '14 at 06:51
  • It is an [ObservableCollection], it still wasn't updating. I'll show my XAML tomorrow if it helps. – Levi Fuller Nov 21 '14 at 06:53
  • No problem. Have you looked into [INotifyPropertyChanged](https://social.msdn.microsoft.com/forums/windowsapps/en-us/2a3e49a8-6000-4707-9dfe-9a1e066eda72/observablecollection-not-updating-correctly)? It might help as well :) – Benjamin Diele Nov 21 '14 at 06:59