Example E4070
Visible to All Users

WinForms Data Grid - CRUD operations (OData)

This example shows how to bind the WinForms Data Grid control to a BindingSource that gets data from OData services.

Unlike the Entity Framework data context, the OData service context does not have automatic change tracking (you must track changes manually). This example demonstrates how to handle grid events to track user edits.

Each time the user changes the value in a cell and commits the row, the GridView raises the RowUpdated event. Handle this event to notify the data context about the change. When a row has been deleted, the GridView raises the RowDeleted event.

C#
private void GridView_RowUpdated(object sender, RowObjectEventArgs e) { if (e.RowHandle == GridControl.NewItemRowHandle) { this.Context.AddToOrders((Order)e.Row); } else { this.Context.UpdateObject(e.Row); } } private void GridView_RowDeleted(object sender, RowDeletedEventArgs e) { this.Context.DeleteObject(e.Row); }
Visual Basic
Private Sub GridView_RowUpdated(sender As Object, e As RowObjectEventArgs) Handles GridView1.RowUpdated If e.RowHandle = GridControl.NewItemRowHandle Then Me.Context.AddToOrders(CType(e.Row, Order)) Else Me.Context.UpdateObject(e.Row) End If End Sub Private Sub GridView_RowDeleted(sender As Object, e As RowDeletedEventArgs) Handles GridView1.RowDeleted Me.Context.DeleteObject(e.Row) End Sub

Files to Review

Documentation

Does this example address your development requirements/objectives?

(you will be redirected to DevExpress.com to submit your response)

Example Code

DxSample/MainForm.cs(vb)
C#
using DevExpress.Data; using DevExpress.XtraBars; using DevExpress.XtraEditors; using DevExpress.XtraGrid; using DevExpress.XtraGrid.Views.Base; using DxSample.Service.Models; using System; using System.Linq; namespace DxSample { public partial class MainForm : XtraForm { Default.Container Context = new Default.Container(new Uri("http://localhost:50936/")); public MainForm() { InitializeComponent(); } private void MainForm_Load(object sender, EventArgs e) { this.customerBindingSource.DataSource = this.Context.Customers.ToList(); this.orderBindingSource.DataSource = this.Context.Orders.ToList(); } private void GridView_RowUpdated(object sender, RowObjectEventArgs e) { if (e.RowHandle == GridControl.NewItemRowHandle) this.Context.AddToOrders((Order)e.Row); else this.Context.UpdateObject(e.Row); } private void GridView_RowDeleted(object sender, RowDeletedEventArgs e) { this.Context.DeleteObject(e.Row); } private void SaveButton_ItemClick(object sender, ItemClickEventArgs e) { this.Context.SaveChanges(); } } }
DxSample.Service/App_Start/WebApiConfig.cs(vb)
C#
using System; using System.Collections.Generic; using System.Linq; using System.Web.Http; using DxSample.Service.Models; using System.Web.OData.Builder; using System.Web.OData.Extensions; namespace DxSample.Service { public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API configuration and services // Web API routes config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); ODataModelBuilder builder = new ODataConventionModelBuilder(); builder.EntitySet<Customer>("Customers"); builder.EntitySet<Order>("Orders"); config.MapODataServiceRoute("ODataRoute", null, builder.GetEdmModel()); } } }
DxSample.Service/Controllers/CustomersController.cs(vb)
C#
using DxSample.Service.Models; using System.Linq; using System.Web.Http; using System.Threading.Tasks; using System.Net; using System.Web.OData; namespace DxSample.Service.Controllers { public class CustomersController :ODataController { private bool CustomerExists(int key) { return DataContext.Customers.Any(c => c.ID == key); } [EnableQuery] public IQueryable<Customer> Get() { return DataContext.Customers; } [EnableQuery] public SingleResult<Customer> Get([FromODataUri] int key) { IQueryable<Customer> result = DataContext.Customers.Where(c => c.ID == key); return SingleResult.Create(result); } public async Task<IHttpActionResult> Post(Customer customer) { if (!this.ModelState.IsValid) return this.BadRequest(this.ModelState); customer = await DataContext.AddCustomer(customer.Name); return this.Created(customer); } public async Task<IHttpActionResult> Patch([FromODataUri] int key, Delta<Customer> customer) { if (!this.ModelState.IsValid) return this.BadRequest(this.ModelState); Customer entity = await DataContext.FindCustomerAsync(key); if (entity == null) return this.NotFound(); customer.Patch(entity); return this.Updated(entity); } public async Task<IHttpActionResult> Put([FromODataUri] int key, Customer update) { if (!this.ModelState.IsValid) return this.BadRequest(this.ModelState); if (key != update.ID) return this.BadRequest(); await DataContext.UpdateCustomer(update); return this.Updated(update); } public async Task<IHttpActionResult> Delete([FromODataUri] int key) { Customer customer = await DataContext.FindCustomerAsync(key); if (customer == null) return this.NotFound(); await DataContext.RemoveCustomer(customer); return this.StatusCode(HttpStatusCode.NoContent); } } }
DxSample.Service/Controllers/OrdersController.cs(vb)
C#
using DxSample.Service.Models; using System.Linq; using System.Web.Http; using System.Threading.Tasks; using System.Net; using System.Web.OData; namespace DxSample.Service.Controllers { public class OrdersController : ODataController { private bool OrderExists(int key) { return DataContext.Orders.Any(c => c.ID == key); } [EnableQuery] public IQueryable<Order> Get() { return DataContext.Orders; } [EnableQuery] public SingleResult<Order> Get([FromODataUri] int key) { IQueryable<Order> result = DataContext.Orders.Where(c => c.ID == key); return SingleResult.Create(result); } public async Task<IHttpActionResult> Post(Order order) { if (!this.ModelState.IsValid) return this.BadRequest(this.ModelState); order = await DataContext.AddOrder(order.Name, order.CustomerID); return this.Created(order); } public async Task<IHttpActionResult> Patch([FromODataUri] int key, Delta<Order> order) { if (!this.ModelState.IsValid) return this.BadRequest(this.ModelState); Order entity = await DataContext.FindOrderAsync(key); if (entity == null) return this.NotFound(); order.Patch(entity); return this.Updated(entity); } public async Task<IHttpActionResult> Put([FromODataUri] int key, Order update) { if (!this.ModelState.IsValid) return this.BadRequest(this.ModelState); if (key != update.ID) return this.BadRequest(); await DataContext.UpdateOrder(update); return this.Updated(update); } public async Task<IHttpActionResult> Delete([FromODataUri] int key) { Order order = await DataContext.FindOrderAsync(key); if (order == null) return this.NotFound(); await DataContext.RemoveOrder(order); return this.StatusCode(HttpStatusCode.NoContent); } } }
DxSample.Service/Models/Customer.cs(vb)
C#
namespace DxSample.Service.Models { public class Customer { public int ID { get; set; } public string Name { get; set; } } }
DxSample.Service/Models/DataContext.cs(vb)
C#
using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace DxSample.Service.Models { public static class DataContext { private static readonly List<Customer> ListCustomers; private static readonly List<Order> ListOrders; private static int CustomersCounter; private static int OrdersCounter; private static readonly object Sync = new object(); static DataContext() { DataContext.ListCustomers = new List<Customer>(); DataContext.ListOrders = new List<Order>(); DataContext.CustomersCounter = 1; DataContext.OrdersCounter = 1; DataContext.AddCustomer("John"); DataContext.AddCustomer("Bob"); DataContext.AddOrder("Chai", 1); DataContext.AddOrder("Chang", 1); DataContext.AddOrder("Queso Caprale", 2); } public static IQueryable<Customer> Customers { get { return DataContext.ListCustomers.AsQueryable(); } } public static IQueryable<Order> Orders { get { return DataContext.ListOrders.AsQueryable(); } } public static Task<Customer> AddCustomer(string name) { return Task.Run<Customer>(() => { lock (DataContext.Sync) { Customer result = new Customer() { ID = DataContext.CustomersCounter++, Name = name }; DataContext.ListCustomers.Add(result); return result; } }); } public static Task<Order> AddOrder(string name, int customerID) { return Task.Run<Order>(() => { lock (DataContext.Sync) { Order result = new Order() { ID = DataContext.OrdersCounter++, Name = name, CustomerID = customerID }; DataContext.ListOrders.Add(result); return result; } }); } public static Task<Customer> FindCustomerAsync(int key) { return Task.Run<Customer>(() => DataContext.Customers.SingleOrDefault(c => c.ID == key)); } public static Task<Order> FindOrderAsync(int key) { return Task.Run<Order>(() => DataContext.Orders.SingleOrDefault(o => o.ID == key)); } public static Task UpdateCustomer(Customer customer) { return Task.Run(() => { Customer original = DataContext.Customers.Single(c => c.ID == customer.ID); int index = DataContext.ListCustomers.IndexOf(original); DataContext.ListCustomers[index] = customer; }); } public static Task UpdateOrder(Order order) { return Task.Run(() => { Order original = DataContext.Orders.Single(o => o.ID == order.ID); int index = DataContext.ListOrders.IndexOf(original); DataContext.ListOrders[index] = order; }); } public static Task RemoveCustomer(Customer customer) { return Task.Run(() => DataContext.ListCustomers.Remove(customer)); } public static Task RemoveOrder(Order order) { return Task.Run(() => DataContext.ListOrders.Remove(order)); } } }
DxSample.Service/Models/Order.cs(vb)
C#
namespace DxSample.Service.Models { public class Order { public int ID { get; set; } public string Name { get; set; } public int CustomerID { get; set; } } }

Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.