Skip to main content
All docs
V23.2

Bind to Virtual Sources

  • 7 minutes to read

This document demonstrates how to use the InfiniteAsyncSource or the PagedAsyncSource virtual source to bind GridControl to a data source.

Sample Data

The IssuesContext DbContext descendant is used as a sample data source in this tutorial.

Tip

The DevExpress virtual sources support Entity Framework, Entity Framework Core, and XPO sources. Refer to the following topic for details: Bind the WPF Data Grid to any Data Source with Virtual Sources.

Install the EntityFramework NuGet package.

EntityFramework NuGet Manager

Add the following code to your application.

Sample Data
using System.Collections.Generic;

public class Issue {
    public int Id { get; set; }
    public string Subject { get; set; }
    public int UserId { get; set; }
    public virtual User User { get; set; }
    public DateTime Created { get; set; }
    public int Votes { get; set; }
    public Priority Priority { get; set; }
    public Issue() {
        Created = DateTime.Now;
    }
}
public enum Priority { Low, BelowNormal, Normal, AboveNormal, High }

public class User {
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public virtual ICollection<Issue> Issues { get; set; }
}
using System;
using System.Data.Entity;
using System.Linq;

public class IssuesContextInitializer
    : DropCreateDatabaseIfModelChanges<IssuesContext> {

    public static void ResetData() {
        using(var context = new IssuesContext()) {
            context.Users.Load();
            context.Users.RemoveRange(context.Users);
            context.SaveChanges();
            CreateData(context);
        }
    }

    protected override void Seed(IssuesContext context) {
        base.Seed(context);
        CreateData(context);
    }

    static void CreateData(IssuesContext context) {
        var users = OutlookDataGenerator.Users
            .Select(x =>
            {
                var split = x.Split(' ');
                return new User() {
                      FirstName = split[0],
                      LastName = split[1]
                };
            })
            .ToArray();
        context.Users.AddRange(users);
        context.SaveChanges();

        var rnd = new Random(0);
        var issues = Enumerable.Range(0, 1000)
            .Select(i => new Issue()
            {
                Subject = OutlookDataGenerator.GetSubject(),
                UserId = users[rnd.Next(users.Length)].Id,
                Created = DateTime.Today.AddDays(-rnd.Next(30)),
                Priority = OutlookDataGenerator.GetPriority(),
                Votes = rnd.Next(100),
            })
            .ToArray();
        context.Issues.AddRange(issues);

        context.SaveChanges();
    }
}
using System.Data.Entity;

public class IssuesContext : DbContext {
    static IssuesContext() {
        Database.SetInitializer(new IssuesContextInitializer());
    }
    public IssuesContext() { }

    protected override void OnModelCreating(DbModelBuilder modelBuilder) {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<Issue>()
            .HasIndex(x => x.Created);

        modelBuilder.Entity<Issue>()
            .HasIndex(x => x.Votes);
    }

    public DbSet<Issue> Issues { get; set; }
    public DbSet<User> Users { get; set; }
}
public static class OutlookDataGenerator {
    static Random rnd = new Random(0);
    static string[] Subjects = new string[] { "Developer Express MasterView. Integrating the control into an Accounting System.",
                                            "Web Edition: Data Entry Page. There is an issue with date validation.",
                                            "Payables Due Calculator is ready for testing.",
                                            "Web Edition: Search Page is ready for testing.",
                                            "Main Menu: Duplicate Items. Someone must review all menu items in the system.",
                                            "Receivables Calculator. Where can I find the complete specs?",
                                            "Ledger: Inconsistency. Please fix it.",
                                            "Receivables Printing module is ready for testing.",
                                            "Screen Redraw. Someone must look at it.",
                                            "Email System. What library are we going to use?",
                                            "Cannot add new vendor. This module doesn't work!",
                                            "History. Will we track sales history in our system?",
                                            "Main Menu: Add a File menu. File menu item is missing.",
                                            "Currency Mask. The current currency mask is completely unusable.",
                                            "Drag & Drop operations are not available in the scheduler module.",
                                            "Data Import. What database types will we support?",
                                            "Reports. The list of incomplete reports.",
                                            "Data Archiving. We still don't have these features in our application.",
                                            "Email Attachments. Is it possible to add multiple attachments? I haven't found a way to do this.",
                                            "Check Register. We are using different paths for different modules.",
                                            "Data Export. Our customers asked us for export to Microsoft Excel."};

    public static readonly string[] Users = new string[] {
        "Peter Dolan",
        "Ryan Fischer",
        "Richard Fisher",
        "Tom Hamlett",
        "Mark Hamilton",
        "Steve Lee",
        "Jimmy Lewis",
        "Jeffrey McClain",
        "Andrew Miller",
        "Dave Murrel",
        "Bert Parkins",
        "Mike Roller",
        "Ray Shipman",
        "Paul Bailey",
        "Brad Barnes",
        "Carl Lucas",
        "Jerry Campbell",
    };

    public static string GetSubject() {
        return Subjects[rnd.Next(Subjects.Length - 1)];
    }

    public static string GetFrom() {
        return Users[rnd.Next(Users.Length)];
    }
    public static Priority GetPriority() {
        return (Priority)rnd.Next(5);
    }
}

Bind the GridControl to Data

  1. Switch to the design view. Open the GridControl‘s Quick Actions and invoke the Items Source Wizard.

    Items Source Wizard

  2. Select the IssuesContext data source.

    WPF GridControl Items Source Wizard

  3. Select the Issue table.

    WPF GridControl Items Source Wizard Table

  4. Select the InfiniteAsyncSource binding model to display data with infinite scrolling. Alternatively, you can select the PagedAsyncSource model to display data in pages.

    WPF GridControl Items Source Wizard Binding Model

  5. Ensure that the Key Property is set to Id.

    WPF GridControl Items Source Wizard Settings

  6. Select Code-Behind to generate binding code in MainWindow.xaml.cs/MainWindow.xaml.vb. To generate binding code in a view model, refer to the MVVM Technique section instead.

    WPF GridControl Items Source Wizard Boilerplate

Run the application.

WPF GridControl InfiniteAsyncSource

MVVM Technique

To generate the binding code in a view model, follow these steps.

Create a ViewModel template that implements ViewModelBase and rebuild the solution:

using DevExpress.Mvvm;

namespace WPFBlankAppWithDatabase {
    public class ViewModel : ViewModelBase {

    }
}

Perform steps 1-5.

Select View Model to add the code to your view model.

Items Source Wizard Boilerplate Code

Click Select a Data Context. Select the ViewModel class and click OK.

WPF GridControl ViewModel

Enable the Set selected class as the data context option and click Finish. Items Source Wizard Generate Data Context

The Items Source Wizard generates data binding code in the ViewModel and specifies data context and GridControl options in XAML. Run the application to see the result.