1

I will try to tell my problem in as simple words as possible. In my UWP app, I am loading the data async wise on my Mainpage.xaml.cs`

public MainPage()
{
    this.InitializeComponent();
    LoadVideoLibrary();
}

private async void LoadVideoLibrary()
{
    FoldersData = new List<FolderData>();
    var folders = (await Windows.Storage.StorageLibrary.GetLibraryAsync
                   (Windows.Storage.KnownLibraryId.Videos)).Folders;
    foreach (var folder in folders)
    {
        var files = (await   folder.GetFilesAsync(Windows.Storage.Search.CommonFileQuery.OrderByDate)).ToList();
        FoldersData.Add(new FolderData { files = files, foldername = folder.DisplayName, folderid = folder.FolderRelativeId });

    }
    }

so this is the code where I am loading up a List of FolderData objects. There in my other page Library.xaml.cs I am using that data to load up my gridview with binding data.

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        try
        {
            LoadLibraryMenuGrid();
        }
        catch { }
    }

    private async void LoadLibraryMenuGrid()
    {
        MenuGridItems = new ObservableCollection<MenuItemModel>();
        var data = MainPage.FoldersData;
        foreach (var folder in data)
        {

            var image = new BitmapImage();
            if (folder.files.Count == 0)
            {
                image.UriSource = new Uri("ms-appx:///Assets/StoreLogo.png");
            }
            else
            {
                for (int i = 0; i < folder.files.Count; i++)
                {
                    var thumb = (await folder.files[i].GetThumbnailAsync(Windows.Storage.FileProperties.ThumbnailMode.VideosView));
                    if (thumb != null) { await image.SetSourceAsync(thumb); break; }

                }
            }

            MenuGridItems.Add(new MenuItemModel
            {
                numberofvideos = folder.files.Count.ToString(),
                folder = folder.foldername,
                folderid = folder.folderid,
                image = image
            });
        }
        GridHeader = "Library";
    }

the problem I am facing is that when i launch my application, wait for a few seconds and then i navigate to my library page, all data loads up properly.

but when i try to navigate to library page instantly after launching the app, it gives an exception that

"collection was modified so it cannot be iterated"

I used the breakpoint and i came to know that if i give it a few seconds the List Folder Data is already loaded properly asyncornously, but when i dnt give it a few seconds, that async method is on half way of loading the data so it causes exception, how can i handle this async situation? thanks

Soner Gönül
  • 97,193
  • 102
  • 206
  • 364
Muhammad Touseef
  • 4,357
  • 4
  • 31
  • 75

2 Answers2

3

What you need is a way to wait for data to arrive. How you fit that in with the rest of the application (e.g. MVVM or not) is a different story, and not important right now. Don't overcomplicate things. For example, you only need an ObservableCollection if you expect the data to change while the user it looking at it.

Anyway, you need to wait. So how do you wait for that data to arrive?

Use a static class that can be reached from everywhere. In there put a method to get your data. Make sure it returns a task that you cache for future calls. For example:

internal class Data { /* whatever */ }

internal static class DataLoader
{
    private static Task<Data> loaderTask;

    public static Task<Data> LoadDataAsync(bool refresh = false)
    {
        if (refresh || loaderTask == null)
        {
            loaderTask = LoadDataCoreAsync();
        }

        return loaderTask;
    }

    private static async Task<Data> LoadDataCoreAsync()
    {
        // your actual logic goes here
    }
}

With this, you can start the download as soon as you start the application.

await DataLoader.LoadDataAsync();

When you need the data in that other screen, just call that method again. It will not download the data again (unless you set refresh is true), but will simply wait for the work that you started earlier to finish, if it is not finished yet.

Kris Vandermotten
  • 10,111
  • 38
  • 49
1

I get that you don't have enough experience.There are multiple issues and no solution the way you are loading the data.

What you need is a Service that can give you ObservableCollection of FolderData. I think MVVM might be out of bounds at this instance unless you are willing to spend a few hours on it. Though MVVM will make things lot easier in this instance.

The main issue at hand is this You are using foreach to iterate the folders and the FolderData list. Foreach cannot continue if the underlying collection changes.

Firstly you need to start using a for loop as opposed to foreach. 2ndly add a state which denotes whether loading has finished or not. Finally use observable data source. In my early days I used to create static properties in App.xaml.cs and I used to use them to share / observe other data.

Hermit Dave
  • 3,036
  • 1
  • 13
  • 13
  • yes it is confusing for me bcz i dnt have much experience in async programming. FolderData is a static list, but its a simple list and not observable list, so i should make it observable ? – Muhammad Touseef Mar 01 '16 at 12:45
  • yes i am it observableColection now it is not giving exception, but when i again try to instantly visit that page, half of my data is loaded, and half isnt. is there a simple way that i can await the method so that i can know when FolderData is filled with all data and so i can proceed using it? if so then please can u guide me? thanks – Muhammad Touseef Mar 01 '16 at 12:51
  • What you need to do is Bind the observable collection to Xaml.. right now you are manually creating items.. with Binding it will automatically update the view when collection gets modified – Hermit Dave Mar 01 '16 at 15:25