Question

I have a WPF application which shows items in a DataGrid (XCeed DataGrid). The app takes a while to load when the database (SQLite) contains lots of items, so I'd like to use yield return if possible to load these on demand. I know the XCeed DataGrid supports UI virtualization, but I'm not entirely sure how to convert the following block of synchronous code.

Currently, the list of loaded in a BackgroundWorker to prevent UI slowdown, the populated as the grid's DataSource.

   public override IList<IRecipe> GetRecipes()
    {
        List<IRecipe> recipes = new List<IRecipe>();
        Execute(conn =>
        {
            using (var cmd = conn.CreateCommand()) {
                cmd.CommandText = "SELECT * FROM recipes  ORDER BY Name";
                var reader = cmd.ExecuteReader();
                while (reader.Read()) {
                    try {
                        var recipe = GetRecipe(reader);
                        recipes.Add(recipe);
                    } catch (Exception ex) {
                        Console.WriteLine(string.Format("Error loading recipe: {0}", ex.Message));
                    }
                }
                reader.Close();

                cmd.CommandText = "SELECT * FROM Ingredients WHERE Recipe = @Recipe";
                cmd.Parameters.AddWithValue("@Recipe", string.Empty);
                foreach (IRecipe recipe in recipes) {
                    cmd.Parameters["@Recipe"].Value = recipe.ID;
                    reader = cmd.ExecuteReader();
                    while (reader.Read()) {
                        try {
                            IIngredient Ingredient = GetIngredient(reader);
                            recipe.Ingredients.Add(Ingredient);
                        } catch (Exception ex) {
                            Console.WriteLine(string.Format("Error adding Ingredient to recipe '{0}': {1}", recipe.Name, ex.Message));
                        }
                    }
                    reader.Close();
                }
            }

Alternatively is there any other way I could improve the speed and use lazy loading?

Was it helpful?

Solution

I'm not familiar exactly with how xceed fetches the virtualized items.
I assume it is by some kind of event that specifies what range of rows that are requested.

In the event (or whatever method that is used) you fetch a range of your query. Use LIMIT and OFFSET as noted at the bottom of the SELECT documentation.

OTHER TIPS

yield return is not your friend here. An iterator block (which is what yield return creates) is simply syntactic sugar for creating a class that implements IEnumerable and a custom enumerator that implements a state machine. This does not actually provide any performance benefit, nor does it necessarily facilitate lazy loading, as the code that it generates will be just as synchronous as the code that you write in it.

I'm not an expert on the Xceed grid, so I can't provide you with an answer that's particular to that product, but lazy loading may indeed help with your problem (to solve it truly, you'll probably have to load as little data as possible to display, then start preemptively loading upcoming data in a background thread, but the details of how to do that are beyond the scope of an answer here).

One approach might be to synchronously load a particular number of rows (whatever is necessary to display at the time), then load the remainder of the rows either as needed (if your data set is large and the user is unlikely to look at all of them) or in the background (if the set is not large or the user is likely to review them all).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top