2009-10-01 7 views
2

J'ai un DataGridView avec des colonnes personnalisées.ArgumentException lors de l'ajout d'une colonne ComboBox à DataGridView avec le même DataSource

Mais quand j'ajoute un "DataGridViewComboBoxColumn" et lui donnent une liste de ma classe de modèle comme DataSource alors j'ai eu l'erreur suivante:

System.ArgumentException: DataGridViewComboBoxCell value is not valid.


Nouveau EDIT: 4/9/2009 "Plus de détails"

J'ai une classe appelée SmsPart a les propriétés suivantes:

public class SmsPart 
{ 
    public int ID 
    public SmsPart Parent 
    public string Name 
    // and more 
} 

J'ai méthode appelée "GetSmsParts" return "List<SmsPart>".

Je souhaite que la colonne Parent dans DataGridView soit ComboBoxColumn pour sélectionner la pièce parent de la pièce sélectionnée.

Donc, pour cette raison, je fait « DataGridViewComboBoxColumn » et réglez est Datasource le même DataSource pour le trou DataGridView « Quelle est la méthode de GetsmsParts »:

DataGridViewComboBoxColumn comboCulomn = new DataGridViewComboBoxColumn(); 
    comboCulomn.DataSource = listParts; 
    comboCulomn.DataPropertyName = "Parent"; 
    comboCulomn.DisplayMember = "Name"; 
    comboCulomn.ValueMember = "ID"; 
    comboCulomn.Name = "Parent"; 
    dgvParts.Columns.Add(comboCulomn); 

Mais je l'ai toujours cette erreur message:

System.ArgumentException: DataGridViewComboBoxCell value is not valid.

Répondre

4

essayez d'attribuer le nom de la zone de données pour la propriété de ValueMemberclm2. Lorsque vous spécifiez que le type de valeur est typeof(smsType), vous n'indiquez pas à la colonne ComboBox le champ à utiliser pour la valeur.

EDIT
Attendez une seconde: Votre smsType un type complexe ou quelque chose? Je ne suis pas sûr si des restrictions s'appliquent ici, mais pour un échantillon, vous devriez utiliser quelque chose comme int ou string ou quelque chose (tout ce que vous attendez normalement d'être stocké comme un champ de base de données). Bien entendu, le type de colonne de la source de données sous-jacente de DataGridView (dans votre exemple appelé "Type") doit également être du même type que le ValueMember!

EDIT 2
Sur votre deuxième commentaire: Imaginez une table de base de données appelée "TBL" qui contient (entre autres) une colonne appelée "Type" qui est de type Integer. Vous affichez le contenu de cette table dans votre DataGridView et vous souhaitez que l'utilisateur puisse sélectionner des valeurs pour la colonne "Type" à partir d'une zone de liste déroulante. C'est à propos du scénario dont vous parlez.

  1. il est impossible de stocker des types complexes comme celui que vous utilisez dans les colonnes de base de données, de sorte que vous ne pouvez pas utiliser des types complexes pour le champ Value dans un DataGridViewComboBoxColumn.
  2. Pour effectuer la liaison de données pour l'ensemble de la grille, vous devez lier la grille à la table de base de données "tbl". Pour créer le DataGridViewComboBoxColumn, vous devez affecter une liste de valeurs possibles à la colonne et indiquer à la colonne le champ dans la source de données de DataGridView dans laquelle elle stocke la valeur sélectionnée, quel champ est utilisé comme valeur d'affichage et quel champ est utilisé comme valeur qui est stocké dans la colonne de la source de données sous-jacente.

Cela signifie que dans l'échantillon (en supposant que la source de données pour la colonne contient des propriétés « Valeur » et « Nom »):

DataGridViewComboBoxColumn col = new ... 
col.DataSource = columnDataSource; 
col.DisplayMember = "Name"; 
col.ValueMember = "Value"; 
col.DataPropertyName = "Type"; 

C'est tout. Cependant, le type de la propriété que vous affectez à "ValueMember" ne peut pas être un type complexe (class/struct) si je me souviens bien ...

+0

Ok, je suis en utilisant le type personnalisé mais pas complexe, il est a seulement deux propriétés "int et string". et pour la deuxième note, je n'ai pas compris ce que vous voulez dire, alors s'il vous plaît expliquer pour moi. Merci beaucoup. –

+0

Je corrige mon code et mets le "ValueMember" à "ID" qui est entier mais qui a toujours la même erreur ?? –

+0

Je viens de lire que DataGridView et Combo Box Column sont réglés sur la même source de données! Je ne pense pas que ce soit possible. Même s'ils contiennent les mêmes données, essayez de créer deux sources de données distinctes, une pour la grille et une pour la colonne. –

4

DataGridViewComboBoxColumn limite l'entrée aux valeurs dans le DataSource. J'ai eu le même problème. J'essayais de définir la valeur du champ en dehors de la DGV. Je liais le DGV à un DataTable. Si je définis un DataRow ["somefield"] à une valeur non dans DataSource, je recevrai l'erreur que vous recevez.

J'ai finalement créé un descendant de DataGridViewColumn qui supporte un éditeur ComboBox et autorisé pour les valeurs qui ne sont pas dans le DataSource.

Je peux poster le code si vous souhaitez le voir.

EDIT: Voici un exemple de colonne ComboBox

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 
using System.ComponentModel; 
using System.Drawing; 
using System.Windows.Forms.VisualStyles; 

namespace YourNamespaceHere 
{ 
    /// <summary> 
    /// DataGridView TextBox column with Items support. 
    /// </summary> 

    public class DropTextBoxColumn : DataGridViewColumn 
    { 
     [Browsable(false)] 
     public IEnumerable<string> Items { get; set; } 

     public ComboBoxStyle DropDownStyle { get; set; } 

     public DropTextBoxColumn() : base(new DropTextBoxCell()) 
     { 
      DropDownStyle = ComboBoxStyle.DropDown; 
     } 

     private DataGridViewCell cellTemplate = new DropTextBoxCell(); 
     public override DataGridViewCell CellTemplate 
     { 
      get 
      { 
       return cellTemplate; 
      } 
      set 
      { 
       // Ensure that the cell used for the template is a DropTextBoxCell. 
       if (value != null && 
        !value.GetType().IsAssignableFrom(typeof(DropTextBoxCell))) 
       { 
        throw new InvalidCastException("Must be a DropTextBoxCell"); 
       } 
       cellTemplate = value; 
      } 
     } 
    } 

    public class DropTextBoxCell : DataGridViewTextBoxCell 
    { 
     [Browsable(false)] 
     public string[] Items { get; set; } 

     public DropTextBoxCell() : base() { } 


     protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts) 
     { 
      base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts); 

      //draw a drop down button 
      if ((cellState & DataGridViewElementStates.Selected) != 0) 
      { 
       var cb = cellBounds; 
       var r = new Rectangle(cb.Right - cb.Height, cb.Top, cb.Height, cb.Height); 
       //ComboBoxRenderer.DrawTextBox(graphics, cb, formattedValue as string, this.Style.Font ?? DataGridView.Font, ComboBoxState.Normal); 
       ComboBoxRenderer.DrawDropDownButton(graphics, r, ComboBoxState.Normal);    
      } 
     } 
     public override void InitializeEditingControl(int rowIndex, object 
      initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle) 
     { 
      // Set the value of the editing control to the current cell value. 
      base.InitializeEditingControl(rowIndex, initialFormattedValue, 
       dataGridViewCellStyle); 
      DropTextBoxEditingControl ctl = 
       DataGridView.EditingControl as DropTextBoxEditingControl; 

      var value = this.Value.ToString(); 

      ctl.Loading = true; 
      DropTextBoxColumn col = DataGridView.Columns[this.ColumnIndex] as DropTextBoxColumn; 
      ctl.DropDownStyle = col.DropDownStyle; 

      ctl.Items.Clear(); 
      if (col.Items != null) 
       ctl.Items.AddRange(col.Items.ToArray()); 

      ctl.EditingControlFormattedValue = value; 
      ctl.Loading = false; 

     } 

     public override Type EditType 
     { 
      get 
      { 
       // Return the type of the editing contol that CalendarCell uses. 
       return typeof(DropTextBoxEditingControl); 
      } 
     } 

     public override Type ValueType 
     { 
      get 
      { 
       // Return the type of the value that CalendarCell contains. 
       return typeof(string); 
      } 
     } 

     public override object DefaultNewRowValue 
     { 
      get 
      { 
       // Use the current date and time as the default value. 
       return string.Empty; 
      } 
     } 
    } 

    class DropTextBoxEditingControl : ComboBox, IDataGridViewEditingControl 
    { 
     DataGridView dataGridView; 
     private bool valueChanged = false; 
     int rowIndex; 
     public bool Loading { get; set; } 
     int originalIndex = -1; 

     public DropTextBoxEditingControl() 
     { 
      //this.Format = DateTimePickerFormat.Short; 
      DropDownStyle = ComboBoxStyle.DropDown; 
      FlatStyle = FlatStyle.Flat;  
     } 

     // Implements the IDataGridViewEditingControl.EditingControlFormattedValue 
     // property. 
     public object EditingControlFormattedValue 
     { 
      get 
      { 
       return Text; 
      } 
      set 
      { 

       if (value is String) 
       { 
        if (DropDownStyle == ComboBoxStyle.DropDown) 
         Text = value.ToString(); 
        else 
        { 
         SelectedIndex = originalIndex = Items.IndexOf(value);       
        }      
       } 
      } 
     } 

     // Implements the 
     // IDataGridViewEditingControl.GetEditingControlFormattedValue method. 
     public object GetEditingControlFormattedValue(
      DataGridViewDataErrorContexts context) 
     { 
      return EditingControlFormattedValue; 
     } 

     // Implements the 
     // IDataGridViewEditingControl.ApplyCellStyleToEditingControl method. 
     public void ApplyCellStyleToEditingControl(
      DataGridViewCellStyle dataGridViewCellStyle) 
     { 
      this.Font = dataGridViewCellStyle.Font; 
     } 

     // Implements the IDataGridViewEditingControl.EditingControlRowIndex 
     // property. 
     public int EditingControlRowIndex 
     { 
      get 
      { 
       return rowIndex; 
      } 
      set 
      { 
       rowIndex = value; 
      } 
     } 

     // Implements the IDataGridViewEditingControl.EditingControlWantsInputKey 
     // method. 
     public bool EditingControlWantsInputKey(
      Keys key, bool dataGridViewWantsInputKey) 
     { 
      // Let the DateTimePicker handle the keys listed. 
      //switch (key & Keys.KeyCode) 
      //{ 
      // case Keys.Left: 
      // case Keys.Up: 
      // case Keys.Down: 
      // case Keys.Right: 
      // case Keys.Home: 
      // case Keys.End: 
      // case Keys.PageDown: 
      // case Keys.PageUp: 
      //  return true; 
      // default: 
      //  return !dataGridViewWantsInputKey; 
      //} 

      return DroppedDown; 

     } 

     // Implements the IDataGridViewEditingControl.PrepareEditingControlForEdit 
     // method. 
     public void PrepareEditingControlForEdit(bool selectAll) 
     { 
      // No preparation needs to be done. 
     } 

     // Implements the IDataGridViewEditingControl 
     // .RepositionEditingControlOnValueChange property. 
     public bool RepositionEditingControlOnValueChange 
     { 
      get 
      { 
       return false; 
      } 
     } 

     // Implements the IDataGridViewEditingControl 
     // .EditingControlDataGridView property. 
     public DataGridView EditingControlDataGridView 
     { 
      get 
      { 
       return dataGridView; 
      } 
      set 
      { 
       dataGridView = value; 
      } 
     } 

     // Implements the IDataGridViewEditingControl 
     // .EditingControlValueChanged property. 
     public bool EditingControlValueChanged 
     { 
      get 
      { 
       return valueChanged; 
      } 
      set 
      { 
       valueChanged = value; 
      } 
     } 

     // Implements the IDataGridViewEditingControl 
     // .EditingPanelCursor property. 
     public Cursor EditingPanelCursor 
     { 
      get 
      { 
       return base.Cursor; 
      } 
     } 
     protected override void OnSelectedItemChanged(EventArgs e) 
     { 
      if (Loading) return; 

      // Notify the DataGridView that the contents of the cell 
      // have changed. 
      valueChanged = true; 
      this.EditingControlDataGridView.NotifyCurrentCellDirty(true); 
      base.OnSelectedItemChanged(e); 
     } 
     protected override void OnSelectedIndexChanged(EventArgs e) 
     { 
      if (Loading || DroppedDown) return; 

      // Notify the DataGridView that the contents of the cell 
      // have changed. 
      valueChanged = true; 
      this.EditingControlDataGridView.NotifyCurrentCellDirty(true); 
      base.OnSelectedIndexChanged(e); 


      SendKeys.Send("{ENTER}"); 
     } 
     protected override void OnTextChanged(EventArgs e) 
     { 
      if (Loading) return; 

      valueChanged = true; 
      this.EditingControlDataGridView.NotifyCurrentCellDirty(true); 
      base.OnTextChanged(e); 
     } 
     protected override void OnDropDownClosed(EventArgs e) 
     { 
      if (originalIndex != SelectedIndex) 
      { 
       valueChanged = true; 
       this.EditingControlDataGridView.NotifyCurrentCellDirty(true); 
      } 
      base.OnDropDownClosed(e); 

     } 
     protected override void OnDropDown(EventArgs e) 
     { 
      //set dropdown width to accomodate items 
      var g = CreateGraphics();  
      DropDownWidth = 
       Items.Cast<string>().Max(s => 
       { 
        var size = g.MeasureString(s, Font); 
        return size.Width.To<int>() + 30; 
       }); 
      base.OnDropDown(e); 
     } 
     protected override void OnEnter(EventArgs e) 
     { 
      base.OnEnter(e); 
      DroppedDown = true; 
     } 
    } 
} 

est ici un exemple d'utilisation

var dc = new DropTextBoxColumn(); 
dc.Name = "FieldName"; 
dc.DataPropertyName = "FieldName"; 
dc.DropDownStyle = ComboBoxStyle.DropDownList; 

var items = dc.Items = new string[]{ "one", "two", "three" }; 
items.Insert(0, "<None>"); 

dc.Items = items; 
DirectGrid.Columns.Insert(1,dc); 
+0

Je voudrais voir ce code, merci! – Hoser

+0

@Hoser - échantillon ajouté. J'espère que cela aide! – Steve

Questions connexes