Real-time data grouping

.Net Grid enables multiple data grouping in headers of the .Net Grid by any columns at any hierarchical level. When data is grouped by a specific column, .Net Grid searches all rows within a group that has similar values. When a group is organized, a row that doesn't contain a data object is added to the data grid. The Row.IsGroup property of such row will always return true, and Row["column id"].Value will return a value by which data is grouped. All rows with values that meet grouping conditions are attached to the newly created group. Before a new data object is added, .Net Grid verifies whether there is any group with the required value on the current hierarchical level. If there is no such group, a new group is created. When the Row.Update() method is invoked, the grid checks whether a row conforms to group value. If there are no more rows in the group, the group is removed from the grid.

In programming the grouping feature can be enabled via the Column.Grouped property. Sequential invocation of this property for several columns results in data grouping of these columns. The column with grouping remains visible unless Column.Visible property is set to false. Sorting (and multiple sorting) can be enabled or disabled for grouped columns because sorting and grouping are completely independent processes. The list of grouped columns can be viewed with Header.GroupedColumns collection property. A user can also group columns in the data grid. To use this ability - user just needs to drag a column to the special panel on the grid's header. However, this is not possible if height of this panel is set to 0.

Grouping and data filtering

When grouping and filtering are enabled simultaneously, the .Net Grid checks every group for visible rows. If there are no visible rows, the group is filtered. If a single unfiltered row appears, the row of the group also becomes visible.

Non-event model

Real-time grouping in non event-driven model is done with Row.Update() method.

public void NonEventModelGrouping(Grid grid)
{
    //Initialize the grid
    grid.Headers.Add(new Header());
    grid.Headers[0].Add(new Column("Name"));
    grid.Headers[0].Add(new Column("Color"));
    grid.Headers[0].Add(new Column("Price"));

    //Group data by color

    grid.Headers[0]["Color"].Grouped = true;

    //Populate the grid
    Row blackMercedes = grid.Rows.Add(new object[] { "Mercedes", Color.Black, 25000d });
    Row whiteMercedes = grid.Rows.Add(new object[] { "Mercedes", Color.White, 23000d });
    Row whiteBMW = grid.Rows.Add(new object[] { "BMW", Color.White, 35000d });

    //The grid has two groups - 1=> black mercedes 2=> white mercedes and bmw

    //The first group has only the black mercedes
    Assert.AreEqual(1, grid.Nodes[0].Children.Count);
    Assert.AreEqual("Mercedes", grid.Nodes[0].Children[0]["Name"].Value);

    //The second group has two cars: white mercedes and white bmw

    Assert.AreEqual(2, grid.Nodes[1].Children.Count);
    Assert.AreEqual("Mercedes", grid.Nodes[1].Children[0]["Name"].Value);
    Assert.AreEqual("BMW", grid.Nodes[1].Children[1]["Name"].Value);

    //Change color of the white mercedes

    whiteMercedes["Color"].Value = Color.Green;

    //Now we have 3 groups. The last contains only the green mercedes
    Assert.AreEqual(1, grid.Nodes[2].Children.Count);
    Assert.AreEqual("Mercedes", grid.Nodes[2].Children[0]["Name"].Value);
    Assert.AreEqual(Color.Green, grid.Nodes[2].Children[0]["Color"].Value);
}

Event-driven model

In the event-driven model Row.Update() method is called every time when a data object sends a notification. Once again we'd like to emphasize the importance of such model as it removes dependency of the business layer on System.Windows.Forms controls and on Dapfor assemblies as well.

Here is the same example for the event-driven model:

//Some data object
public class Car : INotifyPropertyChanged
{
    private readonly string name;
    private readonly double price;
    private Color color;

    public Car(string name, Color color, double price)
    {
        this.name = name;
        this.color = color;
        this.price = price;
    }

    public string Name
    {
        get { return name; }
    }

    public double Price
    {
        get { return price; }
    }

    public Color Color
    {
        get { return color; }
        set
        {
            if (!Equals(color, value))
            {
                color = value;
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("Color"));
                }
            }

        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}


public void EventDrivenModelGrouping(Grid grid)
{
    //Initialize the grid
    grid.Headers.Add(Header.FromDataType(typeof(Car)));

    //Group data by color
    grid.Headers[0]["Color"].Grouped = true;

    //Populate the grid

    Car blackMercedes = new Car("Mercedes", Color.Black, 25000d);
    Car whiteMercedes = new Car("Mercedes", Color.White, 23000d);
    Car whiteBMW = new Car("BMW", Color.White, 35000d);

    grid.Rows.Add(blackMercedes);
    grid.Rows.Add(whiteMercedes);
    grid.Rows.Add(whiteBMW);

    //The grid has two groups - 1=> black mercedes 2=> white mercedes and bmw

    //The first group has only the black mercedes
    Assert.AreEqual(1, grid.Nodes[0].Children.Count);
    Assert.AreEqual("Mercedes", grid.Nodes[0].Children[0]["Name"].Value);

    //The second group has two cars: the white mercedes and the white bmw

    Assert.AreEqual(2, grid.Nodes[1].Children.Count);
    Assert.AreEqual("Mercedes", grid.Nodes[1].Children[0]["Name"].Value);
    Assert.AreEqual("BMW", grid.Nodes[1].Children[1]["Name"].Value);

    //Change color of the white mercedes. NOTE, YOU DO NOT TOUCH THE GRID HERE!!!

    //The car is your business logic and may be placed in any assembly that doesn't have to contain references to Dapfor assemblies!
    whiteMercedes.Color = Color.Green;

    //Now we have 3 groups. The last contains a green mercedes
    Assert.AreEqual(1, grid.Nodes[2].Children.Count);
    Assert.AreEqual("Mercedes", grid.Nodes[2].Children[0]["Name"].Value);
    Assert.AreEqual(Color.Green, grid.Nodes[2].Children[0]["Color"].Value);
}