Simply put, data filtration is managing visibility of rows in the grid. Row invisibility in the grid means that the row is still in the grid, but it is invisible together with its children. It’s important to say that this row can be accessed only via Grid.Nodes/Row.Children collection properties. In the Grid.Rows property invisible rows are absent, as it shows only visible rows. Filtration is particularly important when data is grouped. If there are no visible rows, the whole group becomes invisible (but is not removed!). If a filtered row should be made visible again, it takes certain position according to the sorting rules if any.
.Net Grid presents 3 ways of data filtration:
- Setting boolean in the Row.Filtered property
- Implementing the IFilter interface and setting it with the Grid.Filter property
- Custom filters in columns
The first way is the easiest to use, however, we recommend you to favor the second one that provides definite advantages.
The IFilter interface has only one property – bool IsFiltered(Row row). This method is invoked when data is inserted into the data grid. It is also invoked every time Row.Update() and Grid.FilterRefresh() methods are called. Therefore, grid rows always meed the filtration criteria. However, when IFilter interface is not implemented, the invocation of Row.Update() doesn’t result in data filtration and newly added data is always visible in the grid until the Row.Filtered call. Besides, when filtering conditions are changed, invocation of Grid.FilterRefresh() doesn't make the row visible – the programmer should iterate through every row in the data grid via Grid.Nodes and Row.Children collections to verify new conditions. There is an important thing to add regarding multi-threaded applications. Invocation of IFilter.IsFiltered property occurs regularly in the GUI thread, and it should be considered during development of multi-threaded applications. Please note that Row.Update() method is thread-safe and can be invoked in any thread.
Data filtration implemented via IFilter interface of non-event-driven model consists in the Row.Update() method call.
C# | Copy |
---|---|
public class CustomFilter : IFilter { public bool IsFiltered(Row row) { //There are three ways to get cell's value: //1. Via Cell.Value property: double value = (double)row["Price"].Value //2. Via IDataAccessor and IDataField: double value = (double) row.DataAccessor["Price"].Value //3. Directly from the data object: double value = (double)((IList)row.DataObject)[2]; if ((double)row["Price"].Value < 30000) { //Filter the row return true; } //The row is not filtered return false; } public event EventHandler<EventArgs> FilterUpdated; } public void FilterUsing(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")); //Set filter grid.Filter = new CustomFilter(); //Populate the grid Row row1 = grid.Rows.Add(new object[] { "Mercedes", Color.Black, 25000d}); Assert.IsFalse(row1.Visible); Row row2 = grid.Rows.Add(new object[] { "BMW", Color.White, 35000d }); Assert.IsTrue(row2.Visible); //Set a new price for "Mercedes" row1["Price"].Value = 32000d; Assert.IsTrue(row1.Visible); } |
In the event-driven model (i.e. by implementing INotifyPropertyChanged interface) invocation of Row.Update() method occurs automatically upon receipt of change notification. This means, that you don't have to look for rows in the grid to manage their visibility. All actions occur automatically via INotifyPropertyChanged interface! In other words, a well-designed application should not have any dependencies of the business logic on System.Windows.Forms controls and/or Dapfor controls, and as the result your business logic becomes totally independent and self-reliant.
The same example for the event-driven model:
C# | Copy |
---|---|
//Some data object public class Car : INotifyPropertyChanged { private readonly string name; private readonly Color color; private double price; public Car(string name, Color color, double price) { this.name = name; this.color = color; this.price = price; } public string Name { get { return name; } } public Color Color { get { return color; } } public double Price { get { return price; } set { if (price != value) { price = value; if(PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("Price")); } } } } public event PropertyChangedEventHandler PropertyChanged; } public void FilterUsingInEventDrivemModel(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")); //Set filter grid.Filter = new CustomFilter(); //Populate the grid Car mercedes = new Car("Mercedes", Color.Black, 25000); Car bmw = new Car("BMW", Color.White, 35000); //Insert our data objects into the grid. (Note that they can be inserted into multiple grids with different filtration or sorting!) Row mercedesRow = grid.Rows.Add(mercedes); Row bmwRow = grid.Rows.Add(bmw); //"Mercedes" should be invisible and "BMW" visible Assert.IsFalse(mercedesRow.Visible); Assert.IsTrue(bmwRow.Visible); //Set a new price for "Mercedes". //The car is your business logic and may be placed in any assembly that doesn't have to contain references to Dapfor assemblies! mercedes.Price = 32000; Assert.IsTrue(mercedesRow.Visible); } |