Creating a shared DataSource or binding multiple controls to the same datasource is not a trivial task. It often involves getting data from service, storing it in a JavaScript array, then binding the controls to the array on the client side. When we use this method, though, we end up losing MVC model binding.

Fortunately, ComponentOne MVC Edition control include the CollectionView service, which makes the task of sharing datasources with multiple controls very easy. In addition, change notification is available out-of-the-box—plus you can access this CollectionView on the client-side through its rich API.



Let's look at an example where we'll display monthly country-wide fruit sales data inside a grid, and then summarize it inside a chart. We'll use MVC's FlexChart and FlexGrid controls.

First, we define a simple Fruit model class:



public class Fruit
{
public int ID { get; set; }
public string Name { get; set; }
public int MarPrice { get; set; }
public int AprPrice { get; set; }
public int MayPrice { get; set; }

public string Country { get; set; }

private static List COUNTRIES = new List { "US", "UK", "Canada", "Japan", "China", "France", "German", "Italy", "Korea", "Australia" };
public static IEnumerable GetFruitsSales()
{
var rand = new Random(0);
var fruits = new[] { "Oranges", "Apples", "Pears", "Bananas", "Pineapples",
"Peaches", "Strawberries", "Cherries", "Grapes", "Mangos", "Lemons"};
var list = fruits.Select((f, i) =>
{
int id = i + 1;
int mar = rand.Next(1, 6);
int apr = rand.Next(1, 9);
int may = rand.Next(1, 6);
var country = COUNTRIES[rand.Next(0, COUNTRIES.Count - 1)];
return new Fruit { ID = id, Country = country, Name = f, MarPrice = mar, AprPrice = apr, MayPrice = may };
});

return list;
}
}


Next, we'll define the controller action methods that return data for the controls, along with other CRUD operations:


public class HomeController : Controller
{
public static List fruitsSales = Fruit.GetFruitsSales().ToList();
public ActionResult Index()
{
var settings = new Dictionary<string, object[]>
{
{"ChartType", new object[]{"Column", "Bar", "Scatter", "Line", "LineSymbols", "Area", "Spline", "SplineSymbols", "SplineArea"}},
{"Rotated", new object[]{"False", "True"}}
};
ViewBag.Settings = settings;
return View(fruitsSales);
}

public ActionResult Update([C1JsonRequest]CollectionViewEditRequest requestData)
{
return this.C1Json(CollectionViewHelper.Edit(requestData, fruit =>
{
string error = string.Empty;
bool success = true;
var fSale = fruitsSales.Find(item => item.ID == fruit.ID);
fSale.Name = fruit.Name;
fSale.Country = fruit.Country;
fSale.MayPrice = fruit.MayPrice;
fSale.MarPrice = fruit.MarPrice;
fSale.AprPrice = fruit.AprPrice;
return new CollectionViewItemResult
{
Error = error,
Success = success && ModelState.IsValid,
Data = fSale
};
}, () => fruitsSales));
}

public ActionResult Create([C1JsonRequest]CollectionViewEditRequest requestData)
{
return this.C1Json(CollectionViewHelper.Edit(requestData, fruit =>
{
string error = string.Empty;
bool success = true;
fruit.ID = GetId();
fruitsSales.Add(fruit);
return new CollectionViewItemResult
{
Error = error,
Success = success && ModelState.IsValid,
Data = fruit
};
}, () => fruitsSales));
}

public ActionResult Delete([C1JsonRequest]CollectionViewEditRequest requestData)
{
return this.C1Json(CollectionViewHelper.Edit(requestData, fruit =>
{
string error = string.Empty;
bool success = true;
var fSale = fruitsSales.Find(item => item.ID == fruit.ID);
fruitsSales.Remove(fSale);
return new CollectionViewItemResult
{
Error = error,
Success = success && ModelState.IsValid,
Data = fruit
};
}, () => fruitsSales));
}
}



Now that we have the Model and Controller created, we'll create a view that will display the sales data.



The CollectionViewService class is a server-side datasource that wraps the CollectionView. When sharing this CollectionView with multiple controls, it's important to define this CollectionViewService first.




@(Html.C1().CollectionViewService().Id("fruitsSales")
.Bind(Model).Update(Url.Action("Update", "Home"))
.Delete(Url.Action("Delete", "Home"))
.Create(Url.Action("Create", "Home")))



The service has properties where we can set the CRUD actions from the controller. Each of the MVC controls has an ItemsSourceId property type of CollectionViewServic. This property can be used to share the same datasource.



We define FlexGrid:



@using ASPNetMVCMultipleControlBinding.Models;
@using C1.Web.Mvc;
@model List
<div class="row">
<div class="col-md-5">
<h4>FlexGrid :</h4>
@(Html.C1().FlexGrid().Id("flexGrid")
.Columns(cls =>
{
cls.Add(col => col.Binding("ID").Visible(true).IsReadOnly(true).Width("40"));
cls.Add(col => col.Binding("Name").Width("*"));
cls.Add(col => col.Binding("Country").Width("*"));
cls.Add(col => col.Binding("MarPrice").Width("*"));
cls.Add(col => col.Binding("AprPrice").Width("*"));
cls.Add(col => col.Binding("MayPrice").Width("*"));
})
.IsReadOnly(true)
.AllowSorting(true)
.ItemsSourceId("fruitsSales")
.AutoGenerateColumns(false)
.IsReadOnly(false)
.AllowAddNew(true)
.AllowDelete(true)
.SelectionMode(C1.Web.Mvc.Grid.SelectionMode.Row)
)

</div>
</div>


Now the same CollectionViewService could also be assigned to FlexChart:



<div class="col-md-7">
<h4>FlexChart:</h4>
@(Html.C1().FlexChart().Id("flexChart").Header("Fruits Sales")
.ItemsSourceId("fruitsSales").BindingX("Name").Series(sers =>
{
sers.Add().Binding("MarPrice").Name("March");
sers.Add().Binding("AprPrice").Name("April");
sers.Add().Binding("MayPrice").Name("May");
}).SelectionMode(C1.Web.Mvc.Chart.SelectionMode.Point)
)

</div>


FlexGrid and FlexChart both display data from the same data source, also, FlexChart series will be redrawn when any month's price is changed inside the FlexGrid.



Shared DataSource



Download ComponentOne Studio's Free Trial



  • View the Demo


  • The sample is available to you inside the ~Documents\ComponentOne Samples\ComponentOne MVC\MVC\HowTo\CollectionView samples folder.

  • You will also find the corresponding ASP.NET Core sample inside ~Documents\ComponentOne Samples\ComponentOne MVC\MVC\ASPNETCore\HowTo\CollectionView