使用我的DataSource创建一个DataGridView,它的第二列类型为DataGridViewComboBoxC



我决定重新回答这个问题。给。。。

我有一个XML文件:

<?xml version="1.0" standalone="yes"?>
<GenioCodes>
<Code Layer="BI" Colour="1" />
<Code Layer="BP" Colour="1" />
<Code Layer="BS" Colour="1" />
<Code Layer="C" Colour="1" />
<Code Layer="CC" Colour="1" />
<Code Layer="CR" Colour="1" />
</GenioCodes>

我将其读取为DataSet,并在DataGridView对象上设置为DataSource

m_dataSet.ReadXml(textBoxXML.Text);
m_dataGridView.DataSource = m_dataSet.Tables[0];

DataGridView需要有两列:

列1:这是默认的string列,应绑定到属性。

列2:这需要是DataGridViewComboBoxColumn列,并且应该绑定到颜色属性。

列2单元格对象的类型需要为ComboboxColorItem。类:

public class ComboboxColorItem
{
public string Name { get; set; }
public ushort Index { get; set; }
public Color Value { get; set; }
public ComboboxColorItem(string Name, ushort Index, Color Value)
{
this.Name = Name;
this.Index = Index;
this.Value = Value;
}
public override string ToString()
{
return Name;
}
static public ComboboxColorItem Create(ushort iColourIndex)
{
OdCmColor oColour = new OdCmColor();
oColour.setColorIndex(iColourIndex);
ComboboxColorItem oColorItem = new ComboboxColorItem(
oColour.colorNameForDisplay(),
iColourIndex,
Color.FromArgb(oColour.red(), oColour.green(), oColour.blue()));
oColour.Dispose();
return oColorItem;
}
}

因此,正如您所看到的,XML中的Colour属性只是一个数字。但是我们可以使用静态ComboboxColorItem.Create方法从中创建一个单元格项。

我该如何把这些放在一起?如何使用我的DataSource创建DataGridView,该视图的第二列类型为DataGridViewComboBoxColumn,单元格值类型为ComboboxColorItem

注意:如果需要,我可以更改XML文件的结构。

根据您的问题,我创建了一个使用DataSet的工作示例。IMO,在ComboBox列中使用基元类型更简单。

GetColorFromCode应使用OdCmColor为组合框项目创建颜色和文本。我没有进入那门课的权限。

此示例缺少自定义单元格绘制

public partial class DgvForm : Form
{
private string xml = 
@"<?xml version='1.0' standalone='yes'?>
<GenioCodes>
<Code Layer='BI' Colour='1' Value='qwerty'/>
<Code Layer='BP' Colour='2' />
<Code Layer='BS' Colour='3' Value='Hello'/>
<Code Layer='C' Colour='4' />
<Code Layer='CC' Colour='1' />
<Code Layer='CR' Colour='1' />
</GenioCodes>";
DataSet m_dataSet = new DataSet();
public DgvForm()
{
InitializeComponent();
// reading xml from string
var reader = XmlReader.Create(new StringReader(xml));            
m_dataSet.ReadXml(reader);
m_dataGridView.DataSource = m_dataSet.Tables[0];
var column = m_dataGridView.Columns["Colour"];
int idx = column.Index;
// removing text column
m_dataGridView.Columns.RemoveAt(idx);
// adding comboBox column
var cbo = new DataGridViewComboBoxColumn
{
Name = "Colour",
DataPropertyName = "Colour",
};
// unique color codes for comboBox
var colorCodes = m_dataSet.Tables[0].AsEnumerable()
.Select(r => r["Colour"])
.Distinct()
.ToList();
cbo.DataSource = colorCodes;
// restore column in orignal position
m_dataGridView.Columns.Insert(idx, cbo);
m_dataGridView.EditingControlShowing += ComboBoxShowing;
}
/// <summary>
/// Activates custom drawing in comboBoxes
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ComboBoxShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{            
if (e.Control is ComboBox)
{
ComboBox theCB = (ComboBox)e.Control;
theCB.DrawMode = DrawMode.OwnerDrawFixed;
try
{
theCB.DrawItem -= new DrawItemEventHandler(this.ComboItemDraw);
}
catch { }
theCB.DrawItem += new DrawItemEventHandler(this.ComboItemDraw);
}
}
/// <summary>
/// Custom drawing for comboBox items
/// </summary>
private void ComboItemDraw(object sender, DrawItemEventArgs e)
{
Graphics g = e.Graphics;
Rectangle rDraw = e.Bounds;
rDraw.Inflate(-1, -1);
bool bSelected = Convert.ToBoolean(e.State & DrawItemState.Selected);
bool bValue = Convert.ToBoolean(e.State & DrawItemState.ComboBoxEdit);
rDraw = e.Bounds;
rDraw.Inflate(-1, -1);
if (bSelected & !bValue)
{
g.FillRectangle(Brushes.LightBlue, rDraw);
g.DrawRectangle(Pens.Blue, rDraw);
}
else
{
g.FillRectangle(Brushes.White, e.Bounds);
}

if (e.Index < 0)
return;
string code = ((ComboBox) sender).Items[e.Index].ToString();
Color c = GetColorFromCode(code);
string s = c.ToString();
SolidBrush b = new SolidBrush(c);
Rectangle r = new Rectangle(e.Bounds.Left + 5, e.Bounds.Top + 3, 10, 10);
g.FillRectangle(b, r);
g.DrawRectangle(Pens.Black, r);
g.DrawString(s, Form.DefaultFont, Brushes.Black, e.Bounds.Left + 25, e.Bounds.Top + 1);
b.Dispose();
}
/// <summary>
/// Returns color for a given code 
/// </summary>
/// <param name="code"></param>
/// <returns></returns>
private Color GetColorFromCode(string code)
{
switch (code)
{
case "1": return Color.Green;
case "2": return Color.Cyan;
case "3": return Color.Orange;
case "4": return Color.Gray;
}
return Color.Red;
}
}

尝试迭代每个数据集,然后使用.Rows.Add函数将其绑定到Datagridview。。。

//Creates and Adds Rows for all Data
for (int i = 0; i < DataSet.Count; i++)
{
DataGridView.Rows.Add(new object[] { columnArray1[i], columnArray2[i] });
}

感谢您迄今为止提供的答案,我非常感谢。

按照我的理解,您可以将DataGridView属性AutoGenerateColumns设置为false。此属性未在IDE中公开,但在代码中可用。

如果该属性设置为false,我知道我们可以自己设置DVG列定义,然后只使用DataSet/DataSource组合。因此,我希望避免阅读数据,然后有效地再次阅读数据列(根据当前答案)。

目前,我已经简化了我的代码,以便手动执行操作。因此:

步骤1-初始化DVG:

private void GENIO_Code_Editor_Load(object sender, EventArgs e)
{
try
{
buttonDetect.Enabled = m_dbDatabase != null;
InitColourComboBoxColumn();
dataGridView.Columns.Add("Layer", "Layer");
dataGridView.Columns.Add(cboColumn);
if (textBoxXML.Text != "")
ReadXmlToGrid();
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
}

步骤2:-InitColourComboBoxColumn方法:

private void InitColourComboBoxColumn()
{
try
{
cboColumn = new DataGridViewComboBoxColumn();
cboColumn.Name = "Colour";
cboColumn.ValueMember = "Name";
List<ushort> listColours = new List<ushort>();
listColours.Add(1);
listColours.Add(2);
listColours.Add(3);
listColours.Add(4);
listColours.Add(5);
listColours.Add(6);
listColours.Add(7);
listColours.Add(8);
listColours.Add(9);
listColours.Add(250);
listColours.Add(251);
listColours.Add(252);
listColours.Add(253);
listColours.Add(254);
listColours.Add(255);
foreach (ushort iColourIndex in listColours)
cboColumn.Items.Add(ComboboxColourItem.Create(iColourIndex));
}
catch(Exception ex)
{
throw ex;
}
}

步骤3:实现读取/保存到XML的方法:

private void ReadXmlToGrid()
{
try
{
XmlDocument doc = new XmlDocument();
doc.Load(textBoxXML.Text);
XmlNodeList listCodes = doc.SelectNodes("GenioCodes/Code");
foreach (XmlNode oCode in listCodes)
{
int iRow = dataGridView.Rows.Add();
dataGridView.Rows[iRow].Cells["Layer"].Value = oCode.Attributes["Layer"].Value;
ushort iColourIndex = Convert.ToUInt16(oCode.Attributes["Colour"].Value);
ComboboxColourItem ocbItem2 = null;
foreach (ComboboxColourItem ocbItem in cboColumn.Items)
{
if (ocbItem.Index == iColourIndex)
{
ocbItem2 = ocbItem;
break;
}
}
if (ocbItem2 == null)
{
ocbItem2 = ComboboxColourItem.Create(iColourIndex);
cboColumn.Items.Add(ocbItem2);
}
dataGridView.Rows[iRow].Cells["Colour"].Value = ocbItem2;
}
}
catch(Exception ex)
{
throw ex;
}
}
private void SaveGridToXml()
{
XmlDocument doc = new XmlDocument();
XmlElement codes = doc.CreateElement("GenioCodes");
foreach(DataGridViewRow row in dataGridView.Rows)
{
if(row != null && !row.IsNewRow)
{
XmlElement code = doc.CreateElement("Code");
code.SetAttribute("Layer", row.Cells["Layer"].Value.ToString());
String strThisColour = row.Cells["Colour"].Value.ToString();
bool bColourFound = false;
foreach (ComboboxColourItem ocbItem in cboColumn.Items)
{
if (ocbItem.Name == strThisColour)
{
code.SetAttribute("Colour", ocbItem.Index.ToString());
bColourFound = true;
break;
}
}
if(!bColourFound) // This should not happen
code.SetAttribute("Colour", "1"); // 1 is red
codes.AppendChild(code);
}
}
doc.AppendChild(codes);
doc.Save(textBoxXML.Text);
}

就是这样。它按我的需要工作。如果有一个替代方案,我可以做:

m_DataSet.ReadXml("myfile.xml");
m_DataGridView.DataSource = m_DataSource;
m_DataSet.WriteXml("myfile.xml");

它创建了我想要的DVG类型(没有重读任何专栏或删除),然后我对其他答案很感兴趣,因为我认为这只是解决我问题的一种方法。

最新更新