[英]Problem in databinding Array data to DataGridView in c#
I have been binding short data to DataGridView in C# Winforms.我一直在 C# Winforms 中将短数据绑定到 DataGridView。 However, I need to bind long string array with size 75 to DataGridView.
但是,我需要将大小为 75 的长字符串数组绑定到 DataGridView。 My data list class consists of 6 individual variables with get and set and array of string which I have defined get and set properties.
我的数据列表类由 6 个单独的变量组成,其中包含 get 和 set 以及我定义了 get 和 set 属性的字符串数组。 The individual variables are displayed but the array of strings is not displayed in DataGridView.
显示单个变量,但字符串数组未显示在 DataGridView 中。 In debug, I checked the data source of DataGridView and it seems ok.
在调试中,我检查了 DataGridView 的数据源,似乎没问题。 How can I display binded array in gridview.
如何在 gridview 中显示绑定数组。
Below is my source code to populate DataGridView named Logview下面是我填充名为 Logview 的 DataGridView 的源代码
public void populateLogData(string path)
{
StreamReader sr = null;
BindingList<LogList> bindLogList;
BindingSource bLogsource = new BindingSource();
List<LogList> loglist = new List<LogList>();
try
{
Logview.DataSource = null;
Logview.Rows.Clear();
Logview.Columns.Clear();
Logview.AutoGenerateColumns = true;
if (File.Exists(path))
{
try
{
sr = new StreamReader(path);
StringBuilder readline = new StringBuilder(sr.ReadLine());
if (readline.ToString() != null && readline.ToString() != "")
{
readline = new StringBuilder(sr.ReadLine());
while (readline.ToString() != null && readline.ToString() != "")
{
string[] subdata = readline.ToString().Split(',');
LogList tloglist = new LogList(subdata[0], subdata[1], subdata[2], subdata[3], subdata[4], subdata[5], max_index);
for (int i = 6; i < subdata.Length; i++)
tloglist.setPartList(i-6, subdata[i]);
loglist.Add(new LogList(subdata, subdata.Length));
readline = new StringBuilder(sr.ReadLine());
}
}
bindLogList = new BindingList<LogList>(loglist);
bLogsource.DataSource = bindLogList;
Logview.AutoGenerateColumns = true;
Logview.DataSource = bindLogList;
Logview.Columns[0].Width = 140; // project name
Logview.Columns[1].Width = 140; // data/time
Logview.Columns[2].Width = 90;
Logview.Columns[3].Width = 90;
Logview.Columns[4].Width = 90;
Logview.Columns[5].Width = 90;
// max_index is set from another part of code
for(int i = 0; i <= max_index; i++)
{
int counter = 6 + i;
Logview.Columns.Add(headertext[i], headertext[i]);
Logview.Columns[counter].Width = 90;
Logview.Columns[counter].HeaderText = headertext[i];
}
}
catch (IOException io)
{
MessageBox.Show("Error: Cannot Open log file.");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
if (sr != null) sr.Close();
}
}
else
{
MessageBox.Show("Log file not found \n" + path);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
GC.Collect();
}
}
Below is LogList class下面是 LogList 类
class LogList
{
const int max_size = 100;
private string[] holdList;
public string project { get; set; }
public string date_time { get; set; }
public string Qty { get; set; }
public string Pass { get; set; }
public string Fail { get; set; }
public string Result { get; set; }
public string[] partlist
{
get
{
return holdList;
}
set
{
holdList = value;
}
}
public LogList(string project, string date_time, string Qty, string Pass, string Fail, string Result, int partsize)
{
this.project = project;
this.date_time = date_time;
this.Qty = Qty;
this.Pass = Pass;
this.Fail = Fail;
this.Result = Result;
partlist = new string[partsize+1];
}
public void setPartList(int size, string getValue)
{
partlist[size] = getValue;
}
}
Project, date/time, Qty, Pass, Fail, Result is displayed.显示项目、日期/时间、数量、通过、失败、结果。 But partlist array is not displayed.
但不显示 partlist 数组。
Your data list class consists of 6 individual variables with get
and set
, and an array of string.您的数据列表类由 6 个带有
get
和set
的单独变量和一个字符串数组组成。 Your question is about the variables are displayed but the array of strings is not .你的问题是关于变量被显示但字符串数组不是。
Here's what has worked for me (similar to the excellent suggestion by JohnG) for displaying the string array.这是显示字符串数组的方法(类似于 JohnG 的出色建议)。 What I'm doing here is taking a
DataGridView
and dropping in my main form without changing any settings (other than to Dock
it).我在这里所做的是采用
DataGridView
并在我的主窗体中放置而不更改任何设置(除了Dock
它)。 Given the default settings, the LogList
class (shown here in a minimal reproducible example of 1 variable and 1 array of strings) is defined with a public string property named PartList
and with this basic implementation:给定默认设置,
LogList
类(此处显示为 1 个变量和 1 个字符串数组的最小可重现示例)是使用名为PartList
的公共字符串属性和以下基本实现定义的:
class LogList
{
public LogList(string product, string[] partList)
{
Product = product;
_partList = partList;
}
public string Product { get; set; }
private string[] _partList;
public string PartList => string.Join(",", _partList);
}
To autoconfigure the DataGridView
with Product
and PartList
columns, here is an example initializer method that sets the DataSource
and adds the first three items as a test:要使用
Product
和PartList
列自动配置DataGridView
,下面是一个示例初始化方法,它设置DataSource
并添加前三个项目作为测试:
// Set data source property once. Clear it, Add to it, but no reason to nullify it.
BindingList<LogList> DataSource { get; } = new BindingList<LogList>();
private void InitDataGridView()
{
dataGridView1.DataSource = DataSource;
// Auto config columns by adding at least one Record.
DataSource.Add(
new LogList(
product: "LMG450",
// Four parts
partList: new string[]
{
"PCT2000",
"WCT100",
"ZEL-0812LN",
"EN61000-3-3/-11",
}
));
DataSource.Add(
new LogList(
product: "LMG600N",
// Three parts
partList: new string[]
{
"LTC2280",
"BMS6815",
"ZEL-0812LN",
}
));
DataSource.Add(
new LogList(
product: "Long Array",
// 75 parts
partList: Enumerable.Range(1, 75).Select(x => $"{ x }").ToArray()
));
// Use string indexer to access columns for formatting purposes.
dataGridView1
.Columns[nameof(LogList.Product)]
.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
dataGridView1
.Columns[nameof(LogList.PartList)]
.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
}
After running this code, the DGV looks like this:运行此代码后,DGV 如下所示:
With the mouse hovered over the item all 75 "parts" can be viewed.将鼠标悬停在项目上时,可以查看所有 75 个“部分”。
One last thing - I notice you have some methods to assign a new partList[] of perhaps change an individual part at a specified index.最后一件事 - 我注意到您有一些方法可以分配一个新的 partList[] ,或者更改指定索引处的单个部分。 (I didn't show them in the minimal sample but for sure you'll want things like that).
(我没有在最小样本中展示它们,但你肯定会想要这样的东西)。 You probably know this but make sure to call
dataGridView1.Refresh
after altering properties of an existing row/ LogList
object so that the view will reflect the changes.您可能知道这一点,但请确保在更改现有行/
LogList
对象的属性后调用dataGridView1.Refresh
,以便视图反映更改。
I hope there's something here that offers a few ideas to achieve the outcome you want.我希望这里有一些东西可以提供一些想法来实现你想要的结果。
To supplement IVSoftware's answer, below is an example using two grids in a master-detail scenario.为了补充 IVSoftware 的答案,下面是在主从场景中使用两个网格的示例。
One issue I would have with your current approach, is that it uses an Array for the “parts list.”对于您当前的方法,我会遇到的一个问题是,它使用数组作为“部件列表”。 Currently this is a
string
array, and that isn't going to work if we want to display it in a grid.目前这是一个
string
数组,如果我们想在网格中显示它,那是行不通的。 Fortunately, there are a few easy ways we can get the data to display as we want.幸运的是,有一些简单的方法可以让我们根据需要显示数据。
One simple solution is to create a “wrapper” Class for the string
.一个简单的解决方案是为
string
创建一个“包装”类。 I will call this Class Part
.我将称之为 Class
Part
。 I added a simple int ID
property and the string PartName
property.我添加了一个简单的
int ID
属性和string PartName
属性。 You could easily leave out the ID and have a simple string
wrapper.您可以轻松地省略 ID 并拥有一个简单的
string
包装器。 This simple Class may look something like…这个简单的类可能看起来像……
public class Part {
public int ID { get; set; }
public string PartName { get; set; }
}
This should allow the data to display correctly in the grid using just about any construct like an array, list etc.… So, we “could” change your current code to use an array of Part
objects like…这应该允许使用任何结构(如数组、列表等)在网格中正确显示数据……因此,我们“可以”更改您当前的代码以使用
Part
对象数组,例如……
Part[] Parts = new Parts[X];
And this would work, however, if we use an array and we know for sure that each LogItem
may have a different number of parts in its PartsList
, then we will have to manage the array sizes.但是,如果我们使用数组并且我们确定每个
LogItem
在其PartsList
中可能有不同数量的部分,那么这将起作用,那么我们将不得不管理数组大小。 So, a BindingList
of Part
objects will simplify this.因此,
Part
对象的BindingList
将简化这一点。 The altered LogList
( LogItem
) Class is below…更改后的
LogList
( LogItem
) 类如下……
public class LogItem {
public BindingList<Part> PartsList { get; set; }
public string Project { get; set; }
public string Date_Time { get; set; }
public string Qty { get; set; }
public string Pass { get; set; }
public string Fail { get; set; }
public string Result { get; set; }
public LogItem(string project, string date_Time, string qty, string pass, string fail, string result) {
Project = project;
Date_Time = date_Time;
Qty = qty;
Pass = pass;
Fail = fail;
Result = result;
PartsList = new BindingList<Part>();
}
}
So given the updated Classes, this should simplify things and we will use the same DataSource
for both grids.因此,鉴于更新的类,这应该会简化事情,我们将为两个网格使用相同的
DataSource
。 This DataSource
for the “master” grid will be a BindingList
of LogItem
objects. “主”网格的此
DataSource
将是LogItem
对象的BindingList
。 In the “detail” grid, we simply need to point it's DataMember
property to the PartsList
property of the currently selected LogItem
.在“详细”网格中,我们只需将其
DataMember
属性指向当前选定LogItem
的PartsList
属性。 And this would look something like…这看起来像……
dgvLogs.DataSource = LogsBL;
if (LogsBL.Count > 0) {
dgvParts.DataMember = "PartsList";
dgvParts.DataSource = LogsBL;
}
Below is the code to test the Classes above in a master-detail scenario with two grids.下面是在具有两个网格的主从场景中测试上述类的代码。 Create a new winform solution and drop two (2)
DataGridView
s on the form.创建一个新的 winform 解决方案并在表单上放置两 (2) 个
DataGridView
。 The grid on the left is dgvLogs
and the grid on the right is dgvParts
.左边的网格是
dgvLogs
,右边的网格是dgvParts
。
public void populateLogData(string path) {
BindingList<LogItem> LogsBL = new BindingList<LogItem>();
string currentLine;
if (File.Exists(path)) {
try {
using (StreamReader sr = new StreamReader(path)) {
LogItem tempLogItem;
currentLine = sr.ReadLine(); // <- header row - ignoring
currentLine = sr.ReadLine();
while (currentLine != null) {
if (!string.IsNullOrEmpty(currentLine)) {
string[] splitArray = currentLine.Split(',');
if (splitArray.Length >= 6) {
tempLogItem = new LogItem(splitArray[0], splitArray[1], splitArray[2], splitArray[3], splitArray[4], splitArray[5]);
for (int i = 6; i < splitArray.Length; i++) {
tempLogItem.PartsList.Add(new Part { ID = i, PartName = splitArray[i] });
}
LogsBL.Add(tempLogItem);
}
else {
Debug.WriteLine("DataRead Error: Not enough items to make a LogItem: " + currentLine);
}
}
else {
Debug.WriteLine("DataRead Empty row");
}
currentLine = sr.ReadLine();
}
}
dgvLogs.DataSource = LogsBL;
if (LogsBL.Count > 0) {
dgvParts.DataMember = "PartsList";
dgvParts.DataSource = LogsBL;
}
}
catch (IOException io) {
MessageBox.Show("Error: Cannot Open log file.");
}
catch (Exception ex) {
MessageBox.Show(ex.Message + " Stacktrace- " + ex.StackTrace);
}
}
else {
MessageBox.Show("Log file not found \n" + path);
}
}
And some test data…还有一些测试数据……
H1,h2,h3,h4,h5,h6,h7,h8
Model: LMG600N_IF_2blablas,2022-9-6,112,61,51,Fail,p1,p3,p4,p5,p6
1,2022-9-6,2112,621,251,Pass,px4,px5,px6,px1,px2,px3
data1,2022-9-7,3456,789,123,Fail,z3,z3,z4
Model: LMG600N_IF_2blablas,2022-9-6,112,61,51,Fail
Model: LMG600N_IF_2blablas,2022-9-6,112,61,51,Fail,p1,p3,p4,p5,p6,p7,p8,p99
BadData Model: LMG600N_IF_2blablas,2022-9-6,112,61
Moxxxdel: LMG600N_IF_2blablas,2022-9-6,11x2,6x1,5x1,Fail
Hope this helps and makes sense.希望这会有所帮助并且有意义。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.