如何解决c#根据ComboBox Item Selected填充datagridview
我有这个数据网格,其中 ComboBox 是从 Db 填充的。
我想要实现的是,当我在“Esercizio”列中选择某些内容时,“Video”列的单元格会自动填充 Db 的“link_video”列中的相应值。
所以如果我选择“回扣”,我需要在文本框单元格中看到来自db的回扣链接视频。
这是我用来在表单加载时填充组合框的代码:
private void Myform_Load(object sender,EventArgs e) {
con = new sqlConnection("Data Source=(LocalDB)\\etc");
cmd = new sqlCommand();
con.open();
cmd.Connection = con;
cmd.CommandText = "SELECT * FROM Esercizi";
dr = cmd.ExecuteReader();
while (dr.Read())
{
//populate Column1 comboBox with "nome" column from Esercizi db table
Column1.Items.Add(dr["nome"]);
}
con.Close();
}
编辑 我发现了 2 个新问题。
我正在尝试从 db 加载保存的锻炼,但是当我这样做时,没有视频链接填充 dgv,因为网格事件没有触发。
我尝试的是将 foreach 循环添加到新的 selectionindexchanged 函数中,并在加载按钮代码的末尾触发它,如下所示:
private void curCombo_LoadedValues(object sender,EventArgs e)
{
foreach (DataGridViewRow row in dataGridView1.Rows)
{
foreach (DataGridViewCell cell in row.Cells)
{
if (curCombo != null && curCombo.SelectedValue != null)
{
ExerciseAndVideo selectedExercise = (ExerciseAndVideo)curCombo.SelectedItem;
dataGridView1.CurrentRow.Cells["Video"].Value = selectedExercise.Video;
}
}
}
}
private void button9_Click(object sender,EventArgs e){
string connectionString = "Data Source=(LocalDB)\\etc";
string sql = "SELECT * FROM Schede WHERE Id = 6 AND dgv = 'dataGridView1'";
sqlConnection connection = new sqlConnection(connectionString);
sqlDataAdapter dataadapter = new sqlDataAdapter(sql,connection);using (DataTable dt = new DataTable())
{
dataadapter.Fill(dt);
//Set AutoGenerateColumns False
dataGridView1.AutoGenerateColumns = false;
//Set Columns Count
dataGridView1.ColumnCount = 6;
//Add Columns
dataGridView1.Columns[0].Name = "Esercizio";
dataGridView1.Columns[0].HeaderText = "Esercizio";
dataGridView1.Columns[0].DataPropertyName = "Esercizio";
dataGridView1.Columns[1].Name = "Serie";
dataGridView1.Columns[1].HeaderText = "Serie";
dataGridView1.Columns[1].DataPropertyName = "Serie";
dataGridView1.Columns[2].HeaderText = "Ripetizioni";
dataGridView1.Columns[2].Name = "Ripetizioni";
dataGridView1.Columns[2].DataPropertyName = "Ripetizioni";
dataGridView1.Columns[3].Name = "Recupero";
dataGridView1.Columns[3].HeaderText = "Recupero";
dataGridView1.Columns[3].DataPropertyName = "Recupero";
dataGridView1.Columns[4].Name = "Time Under Tension";
dataGridView1.Columns[4].HeaderText = "Time Under Tension";
dataGridView1.Columns[4].DataPropertyName = "Time_Under_Tension";
dataGridView1.DataSource = dt;
connection.Close();
}
curCombo_LoadedValues();
}
但是我收到这个错误“强制参数发送者没有参数......
如何正确调用它?
第二个问题是,当我像这样填充一些 dgv 列时,组合停止正常工作,并且组合框出现错误异常:
dataGridView1.Rows.Add(7);
Random rnd = new Random();
dataGridView1.Rows[0].Cells[1].Value = 3;
dataGridView1.Rows[0].Cells[2].Value = rnd.Next(1,13);
dataGridView1.Rows[0].Cells[3].Value = 1;
dataGridView1.Rows[0].Cells[4].Value = 201;
dataGridView1.Rows[1].Cells[1].Value = 2;
dataGridView1.Rows[1].Cells[2].Value = rnd.Next(1,13);
dataGridView1.Rows[1].Cells[3].Value = 1;
dataGridView1.Rows[1].Cells[4].Value = 201;
dataGridView1.Rows[2].Cells[1].Value = 3;
dataGridView1.Rows[2].Cells[2].Value = rnd.Next(1,13);
dataGridView1.Rows[2].Cells[3].Value = 1;
dataGridView1.Rows[2].Cells[4].Value = 201;
dataGridView1.Rows[3].Cells[1].Value = 4;
dataGridView1.Rows[3].Cells[2].Value = rnd.Next(1,13);
dataGridView1.Rows[3].Cells[3].Value = 1;
dataGridView1.Rows[3].Cells[4].Value = 201;
dataGridView1.Rows[4].Cells[1].Value = 5;
dataGridView1.Rows[4].Cells[2].Value = rnd.Next(1,13);
dataGridView1.Rows[4].Cells[3].Value = 1;
dataGridView1.Rows[4].Cells[4].Value = 201;
dataGridView1.Rows[5].Cells[1].Value = 6;
dataGridView1.Rows[5].Cells[2].Value = rnd.Next(1,13);
dataGridView1.Rows[5].Cells[3].Value = 1;
dataGridView1.Rows[5].Cells[4].Value = 201;
dataGridView1.Rows[6].Cells[1].Value = 7;
dataGridView1.Rows[6].Cells[2].Value = rnd.Next(1,13);
dataGridView1.Rows[6].Cells[3].Value = 1;
dataGridView1.Rows[6].Cells[4].Value = 201;
这是现在 dgv 的外观: dgv
这是我在组合停止正常工作后得到的错误(我点击并没有出现下拉列表,或者如果我点击 2-3 次,随机项目被选中但没有视频链接出现在另一列中):>
解决方法
我将 ComboBox 与 DatagridViewComboboxColumn 混合在一起。 这部分是你的错:)
这里有一个包含事件的表单。由于 CellValueChanged 在单元格退出时触发,我添加了一个 Dirty StateEvent 来更新 Video 列。 从设计者那里,只需将数据网格放在表单中并确保名称相同。 恕我直言,这三个事件很关键
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Init();
}
private void Init()
{
var list = new List<Exercise>() {
new Exercise (){Name="Name1",Link= "Link1" },new Exercise (){Name="Name3",Link= "Link3" },new Exercise (){Name="Name4",Link= "Link4" },};
var comboColumn = new DataGridViewComboBoxColumn() { Name = "ExerciseName",CellTemplate = new DataGridViewComboBoxCell() };
comboColumn.DisplayMember = nameof(Exercise.Name);
comboColumn.ValueMember = nameof(Exercise.Link);
comboColumn.DataSource = list;
dataGridView1.Columns.Add(comboColumn);
dataGridView1.Columns.Add(new DataGridViewTextBoxColumn() { Name = "Video" });
dataGridView1.CellContentClick += DataGridView1_CellContentClick;
dataGridView1.CellValueChanged += DataGridView1_CellValueChanged;
dataGridView1.CurrentCellDirtyStateChanged += DataGridView1_CurrentCellDirtyStateChanged;
}
private void DataGridView1_CurrentCellDirtyStateChanged(object sender,EventArgs e)
{
var currentCell = (sender as DataGridView).CurrentCell;
if(currentCell.ColumnIndex == 0)
dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
private void DataGridView1_CellValueChanged(object sender,DataGridViewCellEventArgs e)
{
if (e.ColumnIndex != 0)
return;
var comboCell = (dataGridView1.Rows[e.RowIndex].Cells[0] as DataGridViewComboBoxCell);
var value = comboCell.Value;
dataGridView1.Rows[e.RowIndex].Cells["Video"].Value = value;
}
private void DataGridView1_CellContentClick(object sender,DataGridViewCellEventArgs e)
{
}
}
public class Exercise
{
public string Name { get; set; }
public string Link { get; set; }
}
,
在发布的代码中,它显示了对数据库的查询以获取练习名称,并将这些名称添加为要显示在该列的“每个”组合框单元格中的项目。这很好,但是,关于“哪个视频”属于项目组合框列表中的每个项目的信息为零 (0)。我将假设视频与哪个练习相关的“关系”将涉及对 DB 的另一个查询。
如果是这种情况,那么很容易看出,当网格中的组合框发生变化时,您可以简单地查询数据库以了解要用于所选练习的视频。这肯定会奏效;但是,它会产生冗余问题。例如,假设用户在网格的第 1 行的组合框中选择了“踢”。该代码查询数据库并获取“踢”视频的位置并将“视频”单元格设置为该视频路径。然后,用户再次为其他行选择“踢”。这将重新查询数据库以获取我们之前获得的相同数据。您希望避免不必要地查询数据库。
鉴于此,避免不必要地重新查询数据库的更好方法是我们以某种方式将练习与练习使用的特定视频“结合”。您可以在表单加载时执行此操作一次。一旦你有了练习,然后循环每个练习并查询数据库中的练习视频,并将其与练习结合起来。一旦我们有了视频链接,我们就会“保存”这些信息。使用这种方法,您将不必为任何给定的练习重新查询数据库,因为我们已经保存了所有练习的信息。
有无数种方法可以将练习与视频“结合”起来。一种可能的解决方案是创建一个具有这两个属性的类。让我们称这个类为 ExerciseAndVideo
……它有两个属性,一个 string
Exercise
是练习文本,一个 string
Video
定义视频的路径对于那个Exercise
。这个简单的类可能看起来像……
public class ExerciseAndVideo {
public string Exercise { get; set; }
public string Video { get; set; }
}
这是将 Exercise
与特定 Video
“组合”的一种方法。然后我们可以制作一个 ExerciseAndVideo
对象列表,例如……
List<ExerciseAndVideo> ExerciseList;
然后,我们不仅可以将此列表用作组合框列的 DataSource
,而且还可以使用此列表来轻松分辨“哪个”视频属于“哪个”练习。下面的示例使用了这种策略。
如何在DataGridView
...
要记住的一点是,DataGridViewComboBoxCell
与“常规”ComboBox
是“不同的怪物”。例子;对于常规组合框,有一个名为… SelectedIndexChanged
事件的事件。当用户“更改”当前选定索引的组合框时会触发此事件。另一方面,DataGridViewComboBoxCell
没有 SelectedIndexChanged
事件,我假设您可能知道。网格没有这个事件是有道理的,因为网格的组合框“列”可能有很多组合框。
幸运的是,即使 DataGridViewComboBoxCell
没有 SelectedIndexChanged
事件,我们也可以将“单个”组合框单元格转换为 ComboBox
(在这种情况下,组合框单元格是编辑),然后我们可以订阅该 ComboBoxes
SelectedIndexChanged
事件。然后我们可以简单地等待 SelectedIndexChanged
事件触发,然后使用适当的视频链接更新视频单元格数据。
DataGridView
为此提供了一个特殊的事件,称为……EditingControlShowing
。当用户开始“编辑”网格中的单元格时,将触发此事件。在这种特殊情况下,当用户单击组合框单元格并“开始”更改单元格值时,将触发此事件。我们想要在此事件中做的只是将该组合框单元格转换为常规的 ComboBox
...,然后订阅我们将在下面实现的 ComboBoxes
SelectedIndexChanged
事件。>
策略是这样的……我们将创建一个名为 ComboBox
的“全局”curCombo
变量。当 grids EditingControlShowing
事件触发并且我们看到编辑的单元格是一个“练习”单元格时……然后我们将网格中的那个组合框单元格转换为全局 curCombo
变量。然后我们将订阅那个组合框 SelectedIndexChanged
事件。当用户“离开”单元格时,我们将取消订阅全局变量 curCombo
SelectedIndexChanged
事件以保持干净。
因此,鉴于此,grids EditingControlShowing
事件可能如下所示...
private void dataGridView1_EditingControlShowing(object sender,DataGridViewEditingControlShowingEventArgs e) {
if (dataGridView1.Columns[dataGridView1.CurrentCell.ColumnIndex].Name == "Exercise") {
curCombo = e.Control as ComboBox;
if (curCombo != null) {
curCombo.SelectedIndexChanged -= new EventHandler(curCombo_SelectedIndexChanged);
curCombo.SelectedIndexChanged += new EventHandler(curCombo_SelectedIndexChanged);
}
}
}
显然我们需要实现事件处理程序curCombo_SelectedIndexChanged
。在这种情况下,我们会知道之前用户选择了一个组合框单元格并将该单元格中的值更改为某个其他值。由于 Exercise
已更改,我们知道需要更改“视频”单元格。
同样有很多方法可以做到这一点,但是,如果我们将网格的“练习”组合框列的 DataSource
设置为 ExerciseAndVideo
对象的列表,那么我们应该能够得到直接来自全局 ExerciseAndVideo
ComboBox
的特定 curCombo
对象。这将告诉我们将“哪个”视频放置在“视频”单元格中。这可能看起来像……
private void curCombo_SelectedIndexChanged(object sender,EventArgs e) {
if (curCombo != null && curCombo.SelectedValue != null) {
ExerciseAndVideo selectedExercise = (ExerciseAndVideo)curCombo.SelectedItem;
dataGridView1.CurrentRow.Cells["Video"].Value = selectedExercise.Video;
}
}
private void dataGridView1_CellLeave(object sender,DataGridViewCellEventArgs e) {
if (dataGridView1.Columns[e.ColumnIndex].Name == "Exercise") {
if (curCombo != null) {
curCombo.SelectedIndexChanged -= new EventHandler(curCombo_SelectedIndexChanged);
}
}
}
要完成示例并将所有这些放在一起可能会产生如下所示的内容......
List<ExerciseAndVideo> ExerciseList;
ComboBox curCombo;
public Form2() {
InitializeComponent();
}
private void Form2_Load(object sender,EventArgs e) {
ExerciseList = GetExerciseVideoComboBoxListFromDB();
dataGridView1.Columns.Add(GetExcerciseComboBoxColumn(ExerciseList));
dataGridView1.Columns.Add(GetLinkColumn());
dataGridView1.CellLeave += new DataGridViewCellEventHandler(dataGridView1_CellLeave);
dataGridView1.EditingControlShowing += new DataGridViewEditingControlShowingEventHandler(dataGridView1_EditingControlShowing);
}
private DataGridViewComboBoxColumn GetExcerciseComboBoxColumn(List<ExerciseAndVideo> exerciseData) {
DataGridViewComboBoxColumn cbCol = new DataGridViewComboBoxColumn();
cbCol.HeaderText = "Exercise";
cbCol.Name = "Exercise";
cbCol.DisplayMember = "Exercise";
cbCol.DataSource = exerciseData;
return cbCol;
}
private DataGridViewLinkColumn GetLinkColumn() {
DataGridViewLinkColumn col = new DataGridViewLinkColumn();
col.HeaderText = "Video";
col.Name = "Video";
col.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
return col;
}
private List<ExerciseAndVideo> GetExerciseVideoComboBoxListFromDB() {
List<ExerciseAndVideo> exerciseList = new List<ExerciseAndVideo>();
exerciseList.Add(new ExerciseAndVideo { Exercise = "Crosses",Video = @"C:/somepath/Crosses.htm/" });
exerciseList.Add(new ExerciseAndVideo { Exercise = "Kickback",Video = @"C:/somepath/Kickback.htm" });
exerciseList.Add(new ExerciseAndVideo { Exercise = "Leg Extensions",Video = @"C:/somepath/LegExtensions.htm" });
exerciseList.Add(new ExerciseAndVideo { Exercise = "Crunches",Video = @"C:/somepath/Crunches.htm" });
exerciseList.Add(new ExerciseAndVideo { Exercise = "Pushups",Video = @"C:/somepath/Pushups.htm" });
return exerciseList;
}
如果网格有数据源怎么办?
当网格没有数据源时,这会按预期工作。然而,如果网格有一个数据源,并且数据源中的列/属性之一绑定到我们的“练习”组合框列,那么,会发生什么……是在加载数据后,组合框应该显示正确的练习,但是,所有视频单元格将保持为空。这显然是因为加载数据时不触发网格事件。
因此,在这种情况下,您需要一种方法来遍历网格中的所有行,检查该行的练习值是什么,然后将视频单元格值设置为正确的视频链接。由于您没有说明网格是否有数据源,我假设这就是您所需要的。如果有数据源,我建议您检查每个“练习”以确保数据中的“练习”在项目的组合框列表中,如果一个或多个“练习”在数据中不在列表中组合框列的项目列表,那么当您尝试设置网格数据源时,您将获得网格 DataError
。
我希望这是有道理的。
编辑...数据加载到网格后设置视频单元格的示例。
private void SetVideoCellsAfterDataLoad() {
foreach (DataGridViewRow row in dataGridView1.Rows) {
if (!row.IsNewRow && row.Cells["Exercise"].Value != null) {
foreach (ExerciseAndVideo eav in ExerciseList) {
if (row.Cells["Exercise"].Value.ToString() == eav.Exercise) {
row.Cells["Video"].Value = eav.Video;
break;
}
}
}
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。