Reputation: 120
I am trying to create a textbox style filter that would allow me to display only 1 row with selected matching criteria in my dataGridView table.
The table is currently bound to a list object via datasource.
public static List<NpcDrop> npcDrops = new List<NpcDrop>();
//populate npcDrops
dataGridView3.DataSource = Program.npcDrops;
This is set this way so I can edit the value in the dataGridView and the underlying npcDrops list would update itself on cell change. The list is later saved back to the file.
Because of that I cannot convert the list to a DataTable or any other object as this would break the relationship between the dataGridView and the list. I have thought about changing the list to DataTable and then changing it back to the List type but it seems quite impossible to do.
I have tried approaching the problem from various ways:
a) Using BindingSource
BindingSource bs = new BindingSource();
bs.DataSource = Program.npcDrops;
bs.Filter = "npcId like '201001'";
dataGridView3.DataSource = bs;
However the Filter does not seem to be applied (mostly due to fact that the BindingSource based on a List is not IEnumerable.
b) by converting my DataSource to DataTable and then using the RowFilter functionality
private void searchId_TextChanged(object sender, EventArgs e)
{
(dataGridView3.DataSource as DataTable).DefaultView.RowFilter =
string.Format("npcId='{0}'", searchId.Text);
}
this however gave me Object reference not set to an instance of an object. error instead as it seems that it is unable to cast the dataGridView to DataTable.
I have really ran out of the ideas and I am wondering if anyone could help ^^.
Upvotes: 0
Views: 3187
Reputation: 9469
I am guessing you may be meaning a “search” instead of a “filter”. If you want to “search” for something as soon as the user types a character, then in most cases, when the user types a single character into the text box, the searchId_TextChange
event will fire. In this event it appears the code is “filtering” the “Id” from a single character. Unless there is a cell in the table that equals the value the user typed in (which there will not be in this example since it is a single character) … this will most likely leave the grid in an “empty” state to the user because the filter is not going to return any matches.
Therefore, since it appears you want a single row, then that row will not appear until the user types in the “exact” full number. It may be beneficial to possibly wait until the user has typed in x number of characters before you apply the filter. Or simply add a “search” button next to the text box. I am guessing this may be more user friendly.
Lastly, to help, below are two examples of using a List<T>
and a DataTable
as DataSources
to two DataGridViews
I will assume the NpcDrop
property ID
is an int
. In this example ID
is an int
. In the DataTable
example, the ID
is defined as a string
. Add a couple of text boxes and the form may look something like below.
The grid on the left has a List<NcpDrop>
as a data source. The grid on the right used the DataTable
as a DataSource
. Initially fullNPCDropsList
and gridTable
are filled with the same data. The two text boxes TextChanged
events are wired-up to “filter” the grid.
When a “filter” is applied for the List<NcpDrop>
, a new List<NcpDrop>
filterList
is created and filled with all the ID
s that match. This new List<NcpDrop>
is used as the grids DataSource
.
When a “filter” is applied to the DataTable
a new DataView
filterData
is created from the initial DataTalbe
and a RowFilter
is applied to the DataView
based on what text is in the text box. This DataView
is then used as a `DataSource to the grid.
As can be seen from the picture (below) that the left grid will remain “empty” until the user types in the “whole” number. The grid on the right on the other hand will filter the list items when the user types more characters. The grid on the right displays all the items that are like “20102” with five (5) digits. The grid on the left will remain empty until the user types the sixth (6) digit.
In conclusion, it is not clear what the exact requirements are and what would be the best approach from a user perspective. If a user is searching for a number and the data is a number, I am guessing you will need to do more work as this functionality is not available without using equal, less than, greater than etc…
List<NpcDrop> fullNPCDropsList;
DataTable gridTable;
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
fullNPCDropsList = GetData1();
dgvListData.DataSource = fullNPCDropsList;
gridTable = GetData2();
dgvDataTableData.DataSource = gridTable;
}
private List<NpcDrop> GetData1() {
List<NpcDrop> drop = new List<NpcDrop>();
int start = 201000;
for (int i = 0; i < 100; i++) {
drop.Add(new NpcDrop(++start));
}
return drop;
}
private DataTable GetData2() {
DataTable dt = new DataTable();
dt.Columns.Add("ID", typeof(string));
int start = 201000;
for (int i = 0; i < 100; i++) {
dt.Rows.Add((++start).ToString());
}
return dt;
}
private void txtListSearchBox_TextChanged(object sender, EventArgs e) {
if (txtListSearchBox.Text == "") {
dgvListData.DataSource = fullNPCDropsList;
}
else {
if (int.TryParse(txtListSearchBox.Text, out int value)) {
List<NpcDrop> filterList = fullNPCDropsList.FindAll(x => x.ID.Equals(value));
dgvListData.DataSource = filterList;
}
}
}
private void txtDTSearchBox_TextChanged(object sender, EventArgs e) {
if (txtDTSearchBox.Text == "") {
dgvDataTableData.DataSource = gridTable;
}
else {
DataView filterData = new DataView(gridTable);
filterData.RowFilter = "ID LIKE '%" + txtDTSearchBox.Text + "%'";
dgvDataTableData.DataSource = filterData;
}
}
Hope this helps.
Upvotes: 1