使用搜索文本框中的值过滤数据网格视图列表:'Object reference not set to an instance of an object.'
Filter data grid view list with the value from the search text box: 'Object reference not set to an instance of an object.'
我已经设置了一个文本框来在我的数据网格上搜索姓名,但我收到错误消息:'Object reference not set to an instance of an object.'
List<Member> members = new List<Member>();
public class Member
{
public int id { get; set; }
public string name { get; set; }
public int age { get; set; }
public Image image_url { get; set; }
}
// In a keyup event of the text box
(memberGrid.DataSource as DataTable).DefaultView.RowFilter = string.Format("name = '{0}'", searchBox.Text);
我试图将 DataTable
更改为 List
或 Member
。我也尝试过在 DataTable
前面使用 List/Member
进行转换,但它似乎不起作用。
最好的方法是什么?
编辑:
这就是我将 SQL select 中的每一行数据添加到列表中的方式。
members.Add(new Member
{
id = Convert.ToInt32(reader["id"]),
name = reader["name"].ToString(),
age = Convert.ToInt32(reader["age"]),
image_url = (Image)Properties.Resources.ResourceManager.GetObject(reader["image_url"].ToString())
});
为了添加到网格,我遍历列表并为每个成员添加一行:
for (int i = 0; i < members.Count; i++)
{
memberGrid.Rows.Add(new object[]
{
members[i].image_url,
members[i].name,
members[i].age
});
}
因为你没有设置 DataGridView
的 DataSource
并且它是空的,所以当你在这个语句中使用它时收到一个异常:(memberGrid.DataSource as DataTable).DefaultView...
。
不是将行逐一添加到 DataGridView
,而是将数据分配到其 DataSource
。然后根据您使用的数据结构,您可以过滤数据。
您可以使用以下任一解决方案:
作为一个选项,要解决此问题,您可以将数据加载到 DataTable
并将其设置为 DataGridView
的 DataSource
。然后可以按照您尝试的方式进行过滤。
此外,如果出于任何原因您更喜欢 List<Member>
并对其应用过滤器,则在加载数据并转换为 List<Member>
后,请将列表保留在表单中成员字段如 List<Member> members;
然后使用 linq
:
进行过滤
dataGridView1.DataSource = members.Where(x=>x.Name ==searchBox.Text).ToList();
有关详细信息,请阅读 post 中的以下部分。
为什么我收到 NullReferenceException
如果 DataSource
为 null 或 DataSource
不是 DataTable
,则以下代码行将抛出 NullReferenceException
:
(memberGrid.DataSource as DataTable).DefaultView.RowFilter = ...
在你的例子中,你通过添加行来填充数据库并且没有使用它的数据源,所以 DataSource
是空的并且上面的代码抛出异常。
要查找有关如何调试 NullReferenceException
的更多信息,请查看 What is a NullReferenceException, and how do I fix it?。
加载数据
您提到过:
This is how I add each row of data from my SQL select into the list.
members.Add(new Member {
id = Convert.ToInt32(reader["id"]),
name = reader["name"].ToString(),
...
您似乎正在使用 SQL 查询和 SqlDataReader
。那么你不需要使用List<Member>
,一个DataTable
就足够了。您可以将代码更改为以下代码以加载数据:
public DataTable GetData()
{
var dt = new DataTable();
var cn = @"Your Connection String";
var cmd = @"Your Select Command";
using (var da = new SqlDataAdapter(cmd, cn))
da.Fill(dt);
return dt;
}
注意: 如果出于任何原因您有兴趣继续使用 List<Member>
,请将您的代码重构为 return a List<Member>
GetData
:
public List<Member> GetData()
{
var dt = new DataTable();
var cn = @"Your Connection String";
var cmd = @"Your Select Command";
using (var da = new SqlDataAdapter(cmd, cn))
da.Fill(dt);
return dt.AsEnumerable().AsEnumerable().Select(r=>{
id = r.Field<int>("id"),
name = r.Field<string>("name"),
age = r.Field<int>("age")
}).ToList();
}
在 DataGridView 中显示数据
您提到过:
To add to the grid, I loop through the list and add a row per member:
for (int i = 0; i < members.Count; i++) {
memberGrid.Rows.Add(new object[]
...
当您将数据加载到 DataTable
(甚至 List<Member>
)时,您不需要将行逐行添加到 DataGridView
,只需分配数据到DataSource
属性的DataGridView
。
为此,您可以覆盖表单的 OnLoad
方法或处理 Load
事件并将数据加载到数据 table 并将其设置为 DataGridView
:
DataTable dt;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
dt = LoadData();
dataGridView1.DataSource = dt;
}
注意: 如果出于任何原因您更喜欢 returning GetData
中的 List<Member>
,代码将是:
List<Member> members;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
members = LoadData();
dataGridView1.DataSource = members;
}
过滤数据
然后过滤数据,用dt.DefaultView.RowFilter
:
就可以了
dt.DefaultView.RowFilter = string.Format("name = '{0}'", searchBox.Text);
注意: 如果出于任何原因您更喜欢 List<Member>
并对其应用过滤器,请在加载后将列表保存在表单成员中,就像我一样在上面的部分做了,使用linq
过滤数据:
dataGridView1.DataSource = members.Where(x=>x.Name ==searchBox.Text).ToList();
Reza Aghaei 解释了如何解决问题,但如果将来有人可能需要另一种方法来处理这些情况,我就是这样做的。
如上所述,问题是 (memberGrid.DataSource as DataTable).DefaultView.RowFilter = string.Format("name = '{0}'", searchBox.Text);
发生这种情况的原因有 2 个。
- 你
DataSource
没有分配所以is null
- 您分配了
DataTable
以外的其他类型的对象,然后您尝试将其 "back" 转换为 DataTable
所以它 returns null
对于完美的流程,始终将数据绑定到数据源并通过它进行操作。
这是我在我的数据网格视图中的做法。
- 首先我尝试将数据直接加载到 DataTable
因此,如果您从 SQL 加载它,只需使用 DataAdapter
并填写 DataTable
using(SqlConnetion....)
{
con.Open();
using(SqlDataAdapter da ....)
{
DataTable dt = new DataTable();
da.Fill(dt);
dataGridView.DataSource = dt;
//I use this method often because every change i am doing is directly into database and then i just refresh dgv if i need it by loading data again.
}
}
如果直接加载数据 DataTable
由于某些原因对你来说很难(需要自己创建数据表并用 foreach 填充它,但列太多或类似的东西)或者你想在你的内部操作数据代码但不在 DataTable
你可以使用 List<T>
所以简单地创建对象
public class Car
{
public string Model { get; set; }
public Color Color { get; set; }
public string LicencePlate { get; set; }
public doube HP { get; set; }
public Car()
{
}
}
那么假设我们需要从 jsonString
装载汽车,我们会 List<Car> myCars = JsonConverter.Deserialize<List<Car>>(stringFromWebForExample);
现在我们得到了一个列表,我们可以在其中进行操作,但需要将其放入 datagridview 中。同样,我们可以通过 dataGridView.DataSource = myCars
来完成,但是 DataTable
在 datagridview 中显示时比 List
更实用,所以我所做的是使用以下代码将该列表转换为数据表:
public static DataTable ConvertToDataTable<T>(this IList<T> data)
{
PropertyDescriptorCollection properties =
TypeDescriptor.GetProperties(typeof(T));
DataTable table = new DataTable();
foreach (PropertyDescriptor prop in properties)
table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
foreach (T item in data)
{
DataRow row = table.NewRow();
foreach (PropertyDescriptor prop in properties)
row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
table.Rows.Add(row);
}
return table;
}
就叫它 dataGridView.DataSource = myCars.ConvertToDataTable();
这是处理数据并在 DataGridView
中显示数据的两种实用方法
我已经设置了一个文本框来在我的数据网格上搜索姓名,但我收到错误消息:'Object reference not set to an instance of an object.'
List<Member> members = new List<Member>();
public class Member
{
public int id { get; set; }
public string name { get; set; }
public int age { get; set; }
public Image image_url { get; set; }
}
// In a keyup event of the text box
(memberGrid.DataSource as DataTable).DefaultView.RowFilter = string.Format("name = '{0}'", searchBox.Text);
我试图将 DataTable
更改为 List
或 Member
。我也尝试过在 DataTable
前面使用 List/Member
进行转换,但它似乎不起作用。
最好的方法是什么?
编辑:
这就是我将 SQL select 中的每一行数据添加到列表中的方式。
members.Add(new Member
{
id = Convert.ToInt32(reader["id"]),
name = reader["name"].ToString(),
age = Convert.ToInt32(reader["age"]),
image_url = (Image)Properties.Resources.ResourceManager.GetObject(reader["image_url"].ToString())
});
为了添加到网格,我遍历列表并为每个成员添加一行:
for (int i = 0; i < members.Count; i++)
{
memberGrid.Rows.Add(new object[]
{
members[i].image_url,
members[i].name,
members[i].age
});
}
因为你没有设置 DataGridView
的 DataSource
并且它是空的,所以当你在这个语句中使用它时收到一个异常:(memberGrid.DataSource as DataTable).DefaultView...
。
不是将行逐一添加到 DataGridView
,而是将数据分配到其 DataSource
。然后根据您使用的数据结构,您可以过滤数据。
您可以使用以下任一解决方案:
作为一个选项,要解决此问题,您可以将数据加载到
DataTable
并将其设置为DataGridView
的DataSource
。然后可以按照您尝试的方式进行过滤。此外,如果出于任何原因您更喜欢
进行过滤List<Member>
并对其应用过滤器,则在加载数据并转换为List<Member>
后,请将列表保留在表单中成员字段如List<Member> members;
然后使用linq
:dataGridView1.DataSource = members.Where(x=>x.Name ==searchBox.Text).ToList();
有关详细信息,请阅读 post 中的以下部分。
为什么我收到 NullReferenceException
如果 DataSource
为 null 或 DataSource
不是 DataTable
,则以下代码行将抛出 NullReferenceException
:
(memberGrid.DataSource as DataTable).DefaultView.RowFilter = ...
在你的例子中,你通过添加行来填充数据库并且没有使用它的数据源,所以 DataSource
是空的并且上面的代码抛出异常。
要查找有关如何调试 NullReferenceException
的更多信息,请查看 What is a NullReferenceException, and how do I fix it?。
加载数据
您提到过:
This is how I add each row of data from my SQL select into the list.
members.Add(new Member { id = Convert.ToInt32(reader["id"]), name = reader["name"].ToString(), ...
您似乎正在使用 SQL 查询和 SqlDataReader
。那么你不需要使用List<Member>
,一个DataTable
就足够了。您可以将代码更改为以下代码以加载数据:
public DataTable GetData()
{
var dt = new DataTable();
var cn = @"Your Connection String";
var cmd = @"Your Select Command";
using (var da = new SqlDataAdapter(cmd, cn))
da.Fill(dt);
return dt;
}
注意: 如果出于任何原因您有兴趣继续使用 List<Member>
,请将您的代码重构为 return a List<Member>
GetData
:
public List<Member> GetData()
{
var dt = new DataTable();
var cn = @"Your Connection String";
var cmd = @"Your Select Command";
using (var da = new SqlDataAdapter(cmd, cn))
da.Fill(dt);
return dt.AsEnumerable().AsEnumerable().Select(r=>{
id = r.Field<int>("id"),
name = r.Field<string>("name"),
age = r.Field<int>("age")
}).ToList();
}
在 DataGridView 中显示数据
您提到过:
To add to the grid, I loop through the list and add a row per member:
for (int i = 0; i < members.Count; i++) { memberGrid.Rows.Add(new object[] ...
当您将数据加载到 DataTable
(甚至 List<Member>
)时,您不需要将行逐行添加到 DataGridView
,只需分配数据到DataSource
属性的DataGridView
。
为此,您可以覆盖表单的 OnLoad
方法或处理 Load
事件并将数据加载到数据 table 并将其设置为 DataGridView
:
DataTable dt;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
dt = LoadData();
dataGridView1.DataSource = dt;
}
注意: 如果出于任何原因您更喜欢 returning GetData
中的 List<Member>
,代码将是:
List<Member> members;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
members = LoadData();
dataGridView1.DataSource = members;
}
过滤数据
然后过滤数据,用dt.DefaultView.RowFilter
:
dt.DefaultView.RowFilter = string.Format("name = '{0}'", searchBox.Text);
注意: 如果出于任何原因您更喜欢 List<Member>
并对其应用过滤器,请在加载后将列表保存在表单成员中,就像我一样在上面的部分做了,使用linq
过滤数据:
dataGridView1.DataSource = members.Where(x=>x.Name ==searchBox.Text).ToList();
Reza Aghaei 解释了如何解决问题,但如果将来有人可能需要另一种方法来处理这些情况,我就是这样做的。
如上所述,问题是 (memberGrid.DataSource as DataTable).DefaultView.RowFilter = string.Format("name = '{0}'", searchBox.Text);
发生这种情况的原因有 2 个。
- 你
DataSource
没有分配所以is null
- 您分配了
DataTable
以外的其他类型的对象,然后您尝试将其 "back" 转换为DataTable
所以它 returns null
对于完美的流程,始终将数据绑定到数据源并通过它进行操作。 这是我在我的数据网格视图中的做法。
- 首先我尝试将数据直接加载到 DataTable
因此,如果您从 SQL 加载它,只需使用 DataAdapter
并填写 DataTable
using(SqlConnetion....)
{
con.Open();
using(SqlDataAdapter da ....)
{
DataTable dt = new DataTable();
da.Fill(dt);
dataGridView.DataSource = dt;
//I use this method often because every change i am doing is directly into database and then i just refresh dgv if i need it by loading data again.
}
}
如果直接加载数据 DataTable
由于某些原因对你来说很难(需要自己创建数据表并用 foreach 填充它,但列太多或类似的东西)或者你想在你的内部操作数据代码但不在 DataTable
你可以使用 List<T>
所以简单地创建对象
public class Car
{
public string Model { get; set; }
public Color Color { get; set; }
public string LicencePlate { get; set; }
public doube HP { get; set; }
public Car()
{
}
}
那么假设我们需要从 jsonString
装载汽车,我们会 List<Car> myCars = JsonConverter.Deserialize<List<Car>>(stringFromWebForExample);
现在我们得到了一个列表,我们可以在其中进行操作,但需要将其放入 datagridview 中。同样,我们可以通过 dataGridView.DataSource = myCars
来完成,但是 DataTable
在 datagridview 中显示时比 List
更实用,所以我所做的是使用以下代码将该列表转换为数据表:
public static DataTable ConvertToDataTable<T>(this IList<T> data)
{
PropertyDescriptorCollection properties =
TypeDescriptor.GetProperties(typeof(T));
DataTable table = new DataTable();
foreach (PropertyDescriptor prop in properties)
table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
foreach (T item in data)
{
DataRow row = table.NewRow();
foreach (PropertyDescriptor prop in properties)
row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
table.Rows.Add(row);
}
return table;
}
就叫它 dataGridView.DataSource = myCars.ConvertToDataTable();
这是处理数据并在 DataGridView