views:

1433

answers:

3

Hello! I have a windows forms application containing a datagridview control. The datagridview is populated by the contents of an xml file. At the moment, all of the columns are displayed as datagridviewtextboxcolumns. I want to select one that is populated by a particular xml tag and display it's content in a datagridviewcomboboxcolumn along with 2 other options.

EXAMPLE:

<SMS>
<Number>+447931663542</Number> 
<DateTime>2009-07-12T17:00:02</DateTime> 
<Message>YES</Message> 
<FollowedUpBy>Unassigned</FollowedUpBy> 
<Outcome>Resolved</Outcome>
</SMS>

The OUTCOME tag is the column that I would like to be displayed as a comboboxcolumn in the datagridview. If for example the tag is empty and contains no data, then I want to display nothing, but have the comboboxcolumn populated with 3 possible options to choose from (Unresolved, Resolved, Pending). If however the tag contains data, I want that particular item to be displayed in the comboboxcolumn, and have the other two options available to be selected.

Help in achieving this would be appreciated greatly!

Regards,

EDIT: Currently I use this code:

     colOutcome = new DataGridViewComboBoxColumn();
  colOutcome.HeaderText = "Outcome";
  colOutcome.Width = 90;
  colOutcome.Items.AddRange("Resolved", "Unresolved", "Pending");
  this.dataGridView1.Columns.Insert(1, colOutcome);
  this.dataGridView1.Columns[1].Name = "OutcomeColumn";

This code above populates the combobox. THE PROBLEM IS: When The xml document populates the datagridview, the outcome column just appears as a textbox column, containing the data inbetween the outcome tags in the xml file. My point is, how can i get the datagridview to realise when it reads the outcome column that it needs to be changed into a combobox column and then display the data that way, along with the other potentially selectable options in the combobox?! Currently the datagridview gets populated with all columns as textboxcolumns containing the data, as well as a seperate combobox column which is not what I want. I need the application to merge the outcome column and its data with the code above.

Any ideas?

A: 

Updated Answer

You could pass in the XML document to a function that will loop through each node and determine whether it should be a ComboBox one or not i.e. if the name is "Outcome".

private void CreateColumns(XmlDocument doc)
{
    foreach (...) // loop through each node in xml document
    {
         if (node.Name == "Outcome")
         {
              var items = new List<string>() { "Resolved", "Unresolved", "Pending" };
              this.dataGridView1.Columns.Add(CreateComboBoxColumn(node.Name, items));
         }
         else
         {
              this.dataGridView1.Columns.Add(String.Format("col{0}", node.Name), node.Name);
         }
    }
}

Then your code for creating the Outcome column would be:

private DataGridViewComboBoxColumn CreateComboBoxColumn(string colHeaderText, List<string> items)
{
    var colOutcome = new DataGridViewComboBoxColumn(); 
    colOutcome.HeaderText = colHeaderText; 
    colOutcome.Width = 90; 
    colOutcome.Items.AddRange(items.ToArray());
    colOutcome.Name = String.Format("col{0}", colHeaderText);
    return colOutcome;   
}

You would then just call CreateColumns on the form load event and pass in your XML. You should only need to create the columns once.

My advice would be to have a similar function that will find all the SMS elements and add a new row populating it with the information in each node.

public void MyForm_Load(object sender, EventArgs e)
{
     var doc = new XmlDocument(filename);
     CreateColumns(doc);
     CreateRows(doc);
}

Hope that helps.

James
Where did the CheckBoxColumn reference come from? Be careful with this code as it would be called on every column in the DataGridView that is of type DataGridViewComboBoxCell.
Chris Porter
Typo was meant to be ComboBoxCell! Yeah it will get called on every cell that is clicked, but will only be handled by cells that are ComboBoxCells.
James
I don't think I explained myself correctly. See Edit for details.....
Goober
A: 

I'm not sitting in front of VS so this might not compile but should give you direction.

You need to either pre-populate the ResolvedColumn with the 3-4 possible values at design-time or assign it to another datasource at runtime. If you chose the design-time approach, simply open the DataGridView "Edit Columns" dialog, find the ResolvedColumn, go to Items, and add your values ("", "Unresolved", "Pending", "Resolved"). The empty value might help the ComboBox to render if there is the possiblity of rendering the grid with SMS records that have no Outcome.

To bind the possible options at runtime do something like this:

private List<string> _outcomeDataSource;

private void Form1_Load(object sender, EventArgs e)
{
    _outcomeDataSource = new List<string>;
    _outcomeDataSource.Add("");
    _outcomeDataSource.Add("Unresolved");
    _outcomeDataSource.Add("Pending");
    _outcomeDataSource.Add("Resolved");

    ResolvedColumn.DataSource = _outcomeDataSource;
    ResolvedColumn.PropertyName = "Outcome";
}
Chris Porter
your declaration of the List is in VB.NET not C#, should be private List<string> _outcomeDataSource
James
I don't think I explained myself correctly.See Edit for details......
Goober
@James, thanks for catching that. I develop primarily in VB due to client requirements but the question was in C# so I was converting the code in my head. I've updated it to reflect your fix.
Chris Porter
A: 

Answer #2 for me, based on the updated question.

The problem you are experiencing is with the AutoGeneratedColumns functionality of the DataGridView. You will need to create your columns manually before databinding. This can be done at design-time or run-time. I prefer design-time because it gives you a bit more direction with the look/feel of the grid but either way works.

You will need to disable the AutoGeneratedColumns property of the grid:

private void Form1_Load(object sender, EventArgs e)
{
    // Define your columns at run-time here if that's what you prefer

    this.dataGridView1.AutoGeneratedColumns = false;
    this.dataGridView1.DataSource = myDataSource;
}
Chris Porter