I have decided to re-word this question. Here goes ...
I have a XML file:
<?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>
I read it into a DataSet
and set it as a DataSource
on the DataGridView
object:
m_dataSet.ReadXml(textBoxXML.Text);
m_dataGridView.DataSource = m_dataSet.Tables[0];
The DataGridView needs to have two columns:
Column 1 : This is a default string
column and should be bound to the Layer attribute.
Column 2 : This needs to be a DataGridViewComboBoxColumn
column and should be bound to the Colour attribute.
The cell objects for column 2 need to be of type ComboboxColorItem
.The class:
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;
}
}
So, as you can see, the Colour attribute in the XML is just a number. But we can create a cell item from that using the static ComboboxColorItem.Create
method.
How do I put this all together? How can I create a DataGridView, that has the second column of type DataGridViewComboBoxColumn with cell values of type ComboboxColorItem
using my DataSource
?
Note: I can change the structure of the XML file if required.
based on your questions I have created a working examle with a DataSet. IMO, it is simpler to work with primitive type in ComboBox column.
GetColorFromCode
should use OdCmColor
to create a color and text for ComboBox items. I don't have access to that class.
this example lacks custom cell painting
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;
}
}
Try iterating through each Dataset then bind it to the Datagridview using the .Rows.Add function...
//Creates and Adds Rows for all Data
for (int i = 0; i < DataSet.Count; i++)
{
DataGridView.Rows.Add(new object[] { columnArray1[i], columnArray2[i] });
}
Thank you for the answers provided so far, I so appreciate them.
The way I understand it, you can set your DataGridView
property AutoGenerateColumns
to false
. This property is not exposed in the IDE but it is available in code.
If that property is set to false , I understood that we could set the DVG column definitions ourselves and then just use a DataSet
/ DataSource
combination. So I was hoping to avoid reading in the data and then effectively reading the column of data again (as per current answer).
For now, I having simplified my code to do things manually. Thus:
Step 1 - Initialize the 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());
}
}
Step 2: - The InitColourComboBoxColumn
method:
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;
}
}
Step 3: Implement the Read / Save to XML methods:
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);
}
That is it. It works as I need. If there is an alternative where that I can just do:
m_DataSet.ReadXml("myfile.xml");
m_DataGridView.DataSource = m_DataSource;
m_DataSet.WriteXml("myfile.xml");
And it create the type of DVG I am desiring (without re-reading any columns or deleting) then I am interesting in other answers as I considering this just a workaround to my issue.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.