Next topic: .Net Grid tutorial (Part2: Data binding)
The grid provides broad capabilities of working with data such as arbitrary class objects, row arrays, objects implementing IList or IDictionary interfaces and objects with variable number of fields.
Objects of arbitrary classes
Such objects are the main and recommended type of data processed by the grid. A programmer may create any arbitrary classes in application. Objects of these classes are associated with grid rows, and their properties are associated with grid columns. Values returned by getters of these properties are displayed in grid cells.
C# | Copy |
---|---|
public class MyCustomClass { private int _intValue; private double _doubleValue; private string _stringValue; public MyCustomClass(int intValue, double doubleValue, string stringValue) { _intValue = intValue; _doubleValue = doubleValue; _stringValue = stringValue; } public int IntValue { get { return _intValue; } set { _intValue = value; } } public double DoubleValue { get { return _doubleValue; } set { _doubleValue = value; } } public string StringValue { get { return _stringValue; } set { _stringValue = value; } } } //Build a header with columns grid.Headers.Add(new Header()); grid.Headers[0].Add(new Column("IntValue")); grid.Headers[0].Add(new Column("DoubleValue")); grid.Headers[0].Add(new Column("StringValue")); //Add an object of MyCustomClass to a grid: grid.Rows.Add(new MyCustomClass(10, 11.12, "some string 1")); grid.Rows.Add(new MyCustomClass(20, 21.33, "some string 2")); //Other way - bind grid to a BindingList: BindingList<MyCustomClass> bindingList = new BindingList<MyCustomClass>(); bindingList.Add(new MyCustomClass(10, 11.12, "some string 1")); bindingList.Add(new MyCustomClass(20, 21.33, "some string 2")); grid.DataSource = bindingList; |
Object or string arrays
The grid enables work with arrays of strings or any other objects. This method is applicable only to very simple applications. The grid doesn’t set any limitations of data types, however working with untyped data in a large application often causes a lot of errors, makes the code much more complicated and indicates improper application design.
C# | Copy |
---|---|
//Add an array of objects to a grid grid.Rows.Add(new object[] { 10, 11.12, "some string 1" }); grid.Rows.Add(new object[] { 20, 21.33, "some string 2" }); //Bind a collection of arrays to a grid List<object> collection = new List<object>(); collection.Add(new object[] { 10, 11.12, "some string 1" }); collection.Add(new object[] { 20, 21.33, "some string 2" }); grid.DataSource = collection; |
Dictionaries
IDictionary<string, object> can be used for objects with variable number of fields. The key in this container is a string that identifies the data field. If it matches a column identifier, the value of this object is displayed in cell. This method is usually applicable to data not modified by the application. Dictionary<string, object> type objects take a lot of memory. Therefore, it’s not worth bothering to create a lot of such objects. The recommended number of objects of this type shouldn’t exceed 10000 per grid.
C# | Copy |
---|---|
//Add a dictionary to a grid IDictionary<string, object> dataObject1 = new Dictionary<string, object>(); dataObject1.Add("IntValue", 10); dataObject1.Add("StringValue", "some string 1"); grid.Rows.Add(dataObject1); IDictionary<string, object> dataObject2 = new Dictionary<string, object>(); dataObject2.Add("IntValue", 20); dataObject2.Add("DoubleValue", 21.33); grid.Rows.Add(dataObject2); //Bind a collection of dictionaries to a grid BindingList<IDictionary<string, object>> collection = new BindingList<IDictionary<string, object>>(); collection.Add(new Dictionary<string, object>()); collection[0].Add("IntValue", 10); collection[0].Add("StringValue", "some string 1"); collection.Add(new Dictionary<string, object>()); collection[1].Add("IntValue", 20); collection[1].Add("DoubleValue", 21.33); grid.DataSource = collection; |
Variable number of fields with UnboundValueAccessor
Use of UnboundValueAccessor for data with variable number of fields. Its difference from IDictionary is that this container enables grid notification of data modification, and data updating, sorting, grouping and filtering is done automatically.
C# | Copy |
---|---|
//Add an object to the grid grid.Rows.Add(new UnboundValueAccessor()); //Set dynamically some fields grid.Rows[0]["IntValue"].Value = 10; grid.Rows[0]["DoubleValue"].Value = 11.12; //Create and add some other object UnboundValueAccessor dataObject2 = new UnboundValueAccessor(); grid.Rows.Add(dataObject2); //Each modification in dataObject2 will notify the grid dataObject2["IntValue"].Value = 20; dataObject2["DoubleValue"].Value = 21.33; dataObject2["StringValue"].Value = "some string 2"; //The same with binding to a BindingList<UnboundValueAccessor> collection: BindingList<UnboundValueAccessor> collection = new BindingList<UnboundValueAccessor>(); //Populate collection with 2 objects collection.Add(new UnboundValueAccessor()); collection.Add(new UnboundValueAccessor()); //Set some fields in the collection: collection[0]["IntValue"].Value = 10; collection[0]["StringValue"].Value = "some string 1"; collection[1]["StringValue"].Value = "some string 2"; //Bind grid to a colelction grid.DataSource = collection; //Each data modification will notify the grid collection[0]["IntValue"].Value = 55; collection[1]["DoubleValue"].Value = 21.33; |
Event-driven model: A special case of objects of arbitrary classes
As it has been mentioned before, objects of arbitrary classes are recommended for use in the grid. There are many reasons for this. First of all, it is easier and more convenient to work with typed data in applications of high and medium complexity. Besides, objects of arbitrary classes use less memory than string[] objects.
Event-driven model is another important reason to use objects of arbitrary classes. If data objects implement INotifyPropertyChаnged interface, the grid subscribes to events of this object and after receiving notification it automatically sorts, groups and filters them. Updating data in a traditional model requires finding a Row that is associated with data and performing all these operations manually (which is fairly hard). Just compare: MyCustomClass type object is associated with two rows in grid1 and grid2. Grid1 uses sorting and grid2 uses data filtering. Upon change of e.g. IntValue in data object grid1 and grid2 will receive notifications and then grid1 will sort the row to the required position and grid2 will hide it.
This requires only implementation of INotifyPropertyChanged interface in the data object.
C# | Copy |
---|---|
public class MyCustomClass : INotifyPropertyChanged { private int _intValue; ... public MyCustomClass(int intValue, double doubleValue, string stringValue) { _intValue = intValue; ... } public int IntValue { get { return _intValue; } set { if(_intValue != value) { _intValue = value; FirePropertyChanged("IntValue"); } } } public double DoubleValue { ... } public string StringValue { ... } private void FirePropertyChanged(string propertyName) { if(PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } public event PropertyChangedEventHandler PropertyChanged; } //populate both grids with random data: BindingList<MyCustomClass> collection = new BindingList<MyCustomClass>(); Random r = new Random(); for(int i = 0; i < 5; ++i) { collection.Add(new MyCustomClass(i, r.NextDouble(), "some string " + i)); } grid1.DataSource = collection; grid2.DataSource = collection; //Set multiple sorting in the grid1: grid1.Headers[0]["IntValue"].SortDirection = SortDirection.Ascending; grid1.Headers[0]["DoubleValue"].SortDirection = SortDirection.Descending; //Set a filter for the second grid. Grid2 will hide all rows with IntValue > 30 grid2.Filter = new Filter(delegate(Row row) { MyCustomClass dataObject = row.DataObject as MyCustomClass; return dataObject != null && dataObject.IntValue > 30; }); |
Let’s note that in a non-event-driven model implementation of this simple example will require much more code related to searching for rows in the grid and controlling sorting, visibility and filtering.