我需要一些帮助才能使我的代码正常工作。事实证明DataGridView
比我预想的要复杂得多。我需要有人向我展示如何修复我的代码,以便DataGridView
控件可以更新,DataGridViewComboBoxColumn
下拉列表和DataGridViewCheckBoxColumn
控制所有工作。如果你提供的解决方案有点优雅和完整,我对任何策略都没关系。我已经花了太多时间试图解决这个问题。任何想法或建议将不胜感激。
这是我的后端的简化:
MySqlDataAdapter dataAdapter = new MySqlDataAdapter(sqlRequestString, this.dbConnection);
MySqlCommandBuilder commandBuilder = new MySqlCommandBuilder(dataAdapter);
DataTable table = new DataTable();
table.Locale = System.Globalization.CultureInfo.InvariantCulture;
dataAdapter.Fill(table);
bindingSource.DataSource = table;
如果我摆脱BindingSource
,如何将DataTable
直接连接到DataGridView,以便正确填充ComboBox
和Checkbox
列?< / p>
更新
这应该是我尝试初始化DataGridView
的完整概述:
private void InitializeComponent()
{
/* ... */
this.dataGridView1.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.DataGridViewColumn_Section,
this.DataGridViewColumn_Indent,
this.DataGridViewColumn_Content,
this.DataGridViewColumn_Summary,
this.DataGridViewColumn_Role,
this.DataGridViewColumn_Author,
this.DataGridViewColumn_Updated});
this.dataGridView1.Name = "dataGridView1";
this.dataGridView1.DataSourceChanged += new System.EventHandler(this.dataGridView1_DataSourceChanged);
this.dataGridView1.CellEnter += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView1_CellEnter);
this.dataGridView1.CellLeave += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView1_CellLeave);
this.dataGridView1.ColumnAdded += new System.Windows.Forms.DataGridViewColumnEventHandler(this.dataGridView1_ColumnAdded);
this.dataGridView1.SelectionChanged += new System.EventHandler(this.dataGridView1_SelectionChanged);
this.dataGridView1.Leave += new System.EventHandler(this.dataGridView1_Leave);
//
// DataGridViewColumn_Section
//
this.DataGridViewColumn_Section.HeaderText = "Section";
this.DataGridViewColumn_Section.Name = "DataGridViewColumn_Section";
//
// DataGridViewColumn_Indent
//
this.DataGridViewColumn_Indent.HeaderText = "Indent";
this.DataGridViewColumn_Indent.Name = "DataGridViewColumn_Indent";
//
// DataGridViewColumn_Content
//
this.DataGridViewColumn_Content.HeaderText = "Content";
this.DataGridViewColumn_Content.MinimumWidth = 100;
this.DataGridViewColumn_Content.Name = "DataGridViewColumn_Content";
//
// DataGridViewColumn_Summary
//
this.DataGridViewColumn_Summary.HeaderText = "Summary";
this.DataGridViewColumn_Summary.Name = "DataGridViewColumn_Summary";
//
// DataGridViewColumn_Role
//
this.DataGridViewColumn_Role.HeaderText = "Minimum Signoff";
this.DataGridViewColumn_Role.Name = "DataGridViewColumn_Role";
//
// DataGridViewColumn_Author
//
this.DataGridViewColumn_Author.HeaderText = "Author";
this.DataGridViewColumn_Author.Name = "DataGridViewColumn_Author";
this.DataGridViewColumn_Author.ReadOnly = true;
//
// DataGridViewColumn_Updated
//
this.DataGridViewColumn_Updated.HeaderText = "Updated";
this.DataGridViewColumn_Updated.Name = "DataGridViewColumn_Updated";
this.DataGridViewColumn_Updated.ReadOnly = true;
/* ... */
}
public MyWinform()
{
InitializeComponent();
// Initialize DataGridView DataTable
this.dgvDataTable = new DataTable();
// Initialize DataGridView column indexes
this.idxSection = dataGridView1.Columns["DataGridViewColumn_Section"].Index;
this.idxIndent = dataGridView1.Columns["DataGridViewColumn_Indent"].Index;
this.idxContent = dataGridView1.Columns["DataGridViewColumn_Content"].Index;
this.idxSummary = dataGridView1.Columns["DataGridViewColumn_Summary"].Index;
this.idxRole = dataGridView1.Columns["DataGridViewColumn_Role"].Index;
this.idxAuthor = dataGridView1.Columns["DataGridViewColumn_Author"].Index;
this.idxLastUpdate = dataGridView1.Columns["DataGridViewColumn_Updated"].Index;
}
private void MyWinform_Load(object sender, EventArgs e)
{
DataGridView dgv = this.dataGridView1;
DataGridViewComboBoxColumn comboCol;
// Load System Menu
SystemMenu.Load(this.Handle);
// Insert selection prompt
ProcTemplateRecord selectProcPrompt = new ProcTemplateRecord();
selectProcPrompt.PrimaryKey = 0;
selectProcPrompt.ProcName = "Select from the list...";
this.procList.Insert(0, selectProcPrompt);
// Add new procedure prompt
ProcTemplateRecord newProcPrompt = new ProcTemplateRecord();
newProcPrompt.PrimaryKey = -1;
newProcPrompt.ProcName = "Start a new Safe Job Procedure";
this.procList.Add(newProcPrompt);
// Finish initializing the ComboBox dropdown list
this.comboBox1.DataSource = this.procList;
this.comboBox1.DisplayMember = "ProcName";
this.comboBox1.ValueMember = "PrimaryKey";
// Finish initializing DataGridView and bind to BindingSource
this.dataGridView1.AutoGenerateColumns = false;
/*
// Finish initializing the DataGridView ComboBox columns...
comboCol = (DataGridViewComboBoxColumn)dgv.Columns[this.idxSection];
comboCol.DataSource = Enum.GetValues(typeof(SectionType));
comboCol.ValueType = typeof(SectionType);
comboCol.DropDownWidth = ComboBoxMaxLabelWidth(comboCol);
comboCol = (DataGridViewComboBoxColumn)dgv.Columns[this.idxRole];
comboCol.DataSource = Enum.GetValues(typeof(RoleType));
comboCol.ValueType = typeof(RoleType);
comboCol.DropDownWidth = ComboBoxMaxLabelWidth(comboCol);
this.dataGridView1.DataSource = this.dgvDataTable;
*/
this.RefreshDataGridViewColumnWidths();
// Setup post-initialization DataGridViewEvent handlers
this.dataGridView1.CellValueChanged += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView1_CellValueChanged);
this.dataGridView1.CurrentCellDirtyStateChanged += new System.EventHandler(this.dataGridView1_CurrentCellDirtyStateChanged);
}
private void dataGridView1_DataSourceChanged(object sender, EventArgs e)
{
this.RefreshDataGridViewColumnWidths();
}
private void dataGridView1_CellEnter(object sender, DataGridViewCellEventArgs e)
{
DataGridView dgv = (DataGridView)sender;
this.RefreshButtons();
if (e.ColumnIndex == this.idxSection)
{
this.label_dgvToolTip.Visible = false;
}
else if (e.ColumnIndex == this.idxIndent)
{
this.label_dgvToolTip.Visible = false;
}
else if (e.ColumnIndex == this.idxContent)
{
this.label_dgvToolTip.Visible = false;
}
else if (e.ColumnIndex == this.idxSummary)
{
this.label_dgvToolTip.Visible = false;
}
else if (e.ColumnIndex == this.idxRole)
{
this.label_dgvToolTip.Visible = false;
}
else if (e.ColumnIndex == this.idxAuthor)
{
this.label_dgvToolTip.Visible = false;
this.label_dgvToolTip.Text = "Author column values are read only.";
this.label_dgvToolTip.Visible = true;
}
else if (e.ColumnIndex == this.idxLastUpdate)
{
this.label_dgvToolTip.Visible = false;
this.label_dgvToolTip.Text = "Updated column values are read only.";
this.label_dgvToolTip.Visible = true;
}
else
{
this.label_dgvToolTip.Visible = false;
}
this.idxActiveColumn = e.ColumnIndex;
this.idxActiveRow = e.RowIndex;
}
private void dataGridView1_CellLeave(object sender, DataGridViewCellEventArgs e)
{
this.label_dgvToolTip.Visible = false;
this.RefreshButtons();
}
private void dataGridView1_ColumnAdded(object sender, DataGridViewColumnEventArgs e)
{
DataGridView dgv = this.dataGridView1;
if ((e.Column.DataPropertyName == "PageSection") &&
(e.Column.CellType != typeof(DataGridViewComboBoxCell)))
{
var cbo = GetComboBoxColumn(e.Column);
cbo.DataSource = Enum.GetValues(typeof(SectionType));
cbo.ValueType = typeof(SectionType);
dgv.Columns.Remove(e.Column);
dgv.Columns.Add(cbo);
}
else if ((e.Column.DataPropertyName == "UserRole") &&
(e.Column.CellType != typeof(DataGridViewComboBoxCell)))
{
var cbo = GetComboBoxColumn(e.Column);
cbo.DataSource = Enum.GetValues(typeof(RoleType));
cbo.ValueType = typeof(RoleType);
dgv.Columns.Remove(e.Column);
dgv.Columns.Add(cbo);
}
}
private void dataGridView1_SelectionChanged(object sender, EventArgs e)
{
this.RefreshButtons();
}
private void dataGridView1_Leave(object sender, EventArgs e)
{
DataGridView dgv = this.dataGridView1;
if (dgv.SelectedCells.Count == 0)
{
this.idxActiveColumn = -1;
this.idxActiveRow = -1;
}
}
private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
DataGridView dgv = (DataGridView)sender;
DataGridViewComboBoxCell sectionCell = (DataGridViewComboBoxCell)dgv.Rows[e.RowIndex].Cells[this.idxSection];
DataGridViewTextBoxCell indentCell = (DataGridViewTextBoxCell)dgv.Rows[e.RowIndex].Cells[this.idxIndent];
DataGridViewComboBoxCell roleCell = (DataGridViewComboBoxCell)dgv.Rows[e.RowIndex].Cells[this.idxRole];
Int32 colIndex = e.ColumnIndex;
try
{
if (colIndex == this.idxIndent)
{
int number;
string cellValue = indentCell.Value.ToString();
bool isNumeric = int.TryParse(cellValue, out number);
if (!isNumeric)
{
cellValue = cellValue.Substring(0, cellValue.Length - 1);
indentCell.Value = cellValue;
}
}
// Column resizing code goes last
this.RefreshDataGridViewColumnWidths();
this.dgvIsDirty = true;
}
catch (Exception ex)
{
throw new Exception("Failed to refresh DataGridView on cell change.", ex);
}
}
private void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
DataGridView dgv = (DataGridView)sender;
try
{
if (dgv.IsCurrentCellDirty)
{
// This fires the cell value changed handler below
dgv.CommitEdit(DataGridViewDataErrorContexts.Commit);
this.RefreshDataGridViewColumnWidths();
}
}
catch (Exception ex)
{
throw new Exception("Failed to commit edit of DataGridView cell.", ex);
}
}
这是我用来更新DataGridView
控件的代码:
// Load the data from the database into the DataGridView
this.dbif.GetProcedure(this.procList.ElementAt(selectedIndex).PrimaryKey, ref this.dgvDataTable);
DataRow[] rows = this.dgvDataTable.Select();
//Object dgvDataSource = dgv.DataSource;
//dgv.DataSource = null;
foreach (DataRow dataRow in rows)
{
DataGridViewRow dgvRow = new DataGridViewRow();
dgvRow.CreateCells(dgv);
dgvRow.Cells[idxSection].Value = dataRow.Field<string>(0);
dgvRow.Cells[idxIndent].Value = dataRow.Field<byte>(1);
dgvRow.Cells[idxContent].Value = dataRow.Field<string>(3);
dgvRow.Cells[idxSummary].Value = dataRow.Field<UInt32>(4) != 0;
dgvRow.Cells[idxRole].Value = dataRow.Field<string>(5);
dgvRow.Cells[idxAuthor].Value = dataRow.Field<string>(6) + dataRow.Field<string>(7);
dgvRow.Cells[idxLastUpdate].Value = dataRow.Field<DateTime>(8).ToString();
dgv.Rows.Add(dgvRow);
}
//dgv.DataSource = dgvDataSource;
这就是我的枚举的定义方式:
public enum SectionType
{
ESJP_SECTION_HEADER = 1, // start with 1 for database compatibility
ESJP_SECTION_FOOTER,
ESJP_SECTION_BODY
}
public enum RoleType
{
ESJP_ROLE_NONE = 1, // start with 1 for database compatibility
ESJP_ROLE_TEST_ENG,
ESJP_ROLE_FEATURE_LEAD,
ESJP_ROLE_TEAM_LEAD
}
答案 0 :(得分:1)
有许多问题/改进。关于修复所有内容的数据有太多未知数,但这里显示的一些技术可能有所帮助。
你不应该这样做。只需将DataTable
设置为DataSource
即可使用大多数列。
您有两个用于填充dgv的表达式:
dgvRow.Cells[idxSummary].Value = dataRow.Field<UInt32>(4) != 0;
dgvRow.Cells[idxAuthor].Value = dataRow.Field<string>(6) + dataRow.Field<string>(7);
这让我相信dgv是ReadOnly。否则你会遇到麻烦。例如Summary
:如果用户取消选中该列,则可以将该值设置为0,但如果他们检查了该怎么办?你怎么知道要设置什么值?
缩进因为Byte
似乎也很奇怪 - 几乎就像是一个布尔值。
在上一个问题中,dgv是从List<Class>
填充的。使用 作为`DataSource,Enum运行良好,因为2个属性属于该类型。使用枚举,以下工作:
cbo.ValueType = typeof(RoleType);
与此问题的第1版,第2版或第3版一样,使用DataTable
的可能性较小,因为没有db / Datatable类型的{{1} }或SectionType
。在其他情况中有翻译 - 显示用户&#34; ESJP_SECTION_HEADER&#34;但将RoleType
存储在2
中,最终存储在数据库中 - 小DataTable
对列表将起作用。不同的数据模型意味着对DGV cbo采用不同的方法。
现在看起来像是文本列(我已经问了3次)。如果是这样,你真的只需要将选择限制在枚举名称中。在IDE中,粘贴NameValue
属性的文本:
或者,您可以在代码中执行此操作:
Items
<强>的AutoGenerateColumns 强>
当设置DGV的数据源时,默认情况下它会自动为每个DTC列创建一个DGV列,这在大多数情况下效果很好。有时您需要进行一些小调整,例如隐藏private string[] secList = {"ESJP_SECTION_HEADER","ESJP_SECTION_FOOTER",
"ESJP_SECTION_BODY"};
...
((DataGridViewComboBoxColumn)dgv1.Columns["PageSection"]).Items.AddRange(secList);
列,或将TextColumn更改为CBOColumn。 Id
中的代码进行这些更改而不是手动布置列可以很好地工作。
但是由于存在相当多的此类更改,并且由于您已经在IDE中布置了列,因此您希望确保在代码中的某处将ColumnAddedEvent
设置为false。否则它会添加更多列。
您在DGV设计师中可能会或可能不会做的事情:
AutoGenerateColumns
分配给SQL查询中使用的名称。将作者留空。
DataPropertyName
这样的表达式列意味着更改查询或在DGV中进行一些格式化。为此,请将 First 和 Last 名称列添加到DGV以及“作者”列。让前两个看不见。下面的代码显示了格式。 (确保在部件后出现复合列(作者)。)。Author
,但如果您不想弄乱该查询,则可以在DGV事件中进行连接。SELECT (First + Last) AS Author
和Page
列的名称添加到Role
集合。然后,其余的很简单:
Items
格式化事件:
private DataTable dtF;
...
string SQL = "SELECT PageSection, Indent, Content, SummaryId, "
+ "UserRole, AuthorFirstN, AuthorLastN, LastUpdated FROM FellPage";
using (var dbCon = new MySqlConnection(MySQLConnStr))
using (var cmd = new MySqlCommand(SQL, dbCon))
{
dbCon.Open();
dtF = new DataTable();
dtF.Load(cmd.ExecuteReader());
}
// IMPORTANT!!!
dgv1.AutoGenerateColumns = false;
dgv1.DataSource = dtF;
结果:
关闭private void dgv1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (dgv1.Rows[e.RowIndex].IsNewRow)
return;
if (e.ColumnIndex == 7) // ie "Author"
{
e.Value = dgv1.Rows[e.RowIndex].Cells[6].Value.ToString() + ", " +
dgv1.Rows[e.RowIndex].Cells[5].Value.ToString();
e.FormattingApplied = true;
}
}
非常重要。默认情况下,dgv将为源中的所有内容添加列。由于您添加了它们,因此在代码中将其设置为false(没有IDE属性)。
由于AutoGenerateColumns
和Summary
被定义为检查列,它将非零转换为true。 我不知道你将如何编辑任何Indent
值。 这应该是一个文本列,以便他们可以输入一个值,如果允许的话(那个col也可以只读?)。
我的查询和你的查询并不复杂,当然有一些细节我/我们不知道哪些已被省略。但是肯定会有更少的旋转和代码来使它工作......不管这是什么。
绑定到SummaryId
,当用户编辑任何内容时,更改会流向基础DataTable
(使用各种DataTable
事件检查其工作)。 Validating
依次跟踪每一行的状态 - 新增,更改,删除 - 以便稍后您可以:
DataTable
这将返回自上一个var changes = dtF.GetChanges();
以来已更改的所有行。