Ho un DataGridView con colonne "Tipo" e "Valore". L'utente seleziona un tipo di dati, quindi inserisce un valore compatibile con quel tipo, alcuni tipi (ad esempio "Testo") accettano qualsiasi stringa. Altri tipi (ad es. "Sì/No") sono limitati a un elenco di valori possibili. Per ciascuna riga, imposto la cella nella colonna "Valore" in modo che sia una casella di testo per i tipi di forma libera o una casella combinata per i tipi di elenco. DataGridView è associato a un DataTable.Vuota cella Datagridview con dataset associato
Il problema si verifica se l'utente immette un valore per un tipo, ma poi passa la riga a un tipo diverso per il quale il valore corrente non è consentito. Non importa cosa cerco, non posso cancellare la cella Value. Quindi quando assegno una casella combinata alla cella, ottengo un'eccezione DataError, perché il valore corrente della cella non è compatibile. Come posso cancellare il valore prima di cambiare la cella da una casella di testo in una casella combinata?
public enum DataType
{
Text,
YesNo
}
public class IndexedItem
{
public string Name { get; set; }
public int ID {get; set; }
public string strID
{
get { return ID.ToString(); }
}
//constructors & other methods;
}
public static DataTable ParameterTable;
public List<IndexedItem> YesNoList;
Nel costruttore modulo (dgvInputs è DataGridView):
ParameterTable = new DataTable("ParameterTable");
ParameterTable.Columns.Add("Type", typeof(DataType));
ParameterTable.Columns.Add("Value", typeof(string));
YesNoList = new List<IndexedItem>();
YesNoList.Add(new IndexedItem("Yes", 1));
YesNoList.Add(new IndexedItem("No", 0));
var D = (DataGridViewComboBoxColumn)dgvInputs.Columns[0];
D.ValueMember = "Value";
D.DisplayMember = "Display";
D.DataSource = new DataType[] {
DataType.Text,
DataType.YesNo
}.Select(x => new { Display = x.ToString(), Value = (int)x }).ToList();
BindingSource ParamSource = new BindingSource();
ParamSource.DataSource = ParameterTable;
dgvInputs.AutoGenerateColumns = false;
dgvInputs.DataSource = ParamSource;
dgvInputs.Columns[0].DataPropertyName = "Type";
dgvInputs.Columns[1].DataPropertyName = "Value";
ed eventi:
private void dgvInputs_CurrentCellDirtyStateChanged(object sender, EventArgs e) {
if (dgvInputs.IsCurrentCellDirty) {
dgvInputs.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
}
private void dgvInputs_CellValueChanged(object sender, DataGridViewCellEventArgs e) {
if (e.RowIndex >= 0 && e.ColumnIndex == 0) {
var cb = (DataGridViewComboBoxCell)dgvInputs[0, e.RowIndex];
if (cb.Value != null && cb.Value != DBNull.Value) {
DataType Type = (DataType)cb.Value;
dgvInputs[1, e.RowIndex].Value = string.Empty;
dgvInputs.CommitEdit(DataGridViewDataErrorContexts.Commit);
switch (Type) {
case DataType.YesNo:
dgvInputs[1, e.RowIndex].Dispose();
var newBox = new DataGridViewComboBoxCell();
newBox.DisplayMember = "Name";
newBox.ValueMember = "strID";
newBox.DataSource = YesNoList;
dgvInputs[1, e.RowIndex] = newBox;
break;
default:
dgvInputs[1, e.RowIndex] = new DataGridViewTextBoxCell();
break;
}
}
}
}
Se lo avete impostato su "testo" e immettere qualcosa di arbitrario, allora passa a "YesNo", restituisce un errore "System.ArgumentException: DataGridViewComboBoxCell valore non valido.", che riapparirà ogni volta che il cursore si trova sopra la cella. La modifica di una riga di testo fa riapparire il valore originale.
Suppongo che il problema è che il valore viene salvato in ParameterTable, ma non riesco a farlo propagare la cancellazione del valore originale in ParameterTable. Ho provato null
e DBNull.Value
invece di string.Empty
, ma nessuno dei due ha fatto alcuna differenza. Ho aggiunto la riga "CommitEdit" nella speranza di ottenere il cambiamento, ma non ha fatto nessuna differenza.
Edit: Come si è visto, il problema era questo codice che ho avuto in caso di cambiamento di cella:
string Default = dgvInputs[4, e.RowIndex].Value as string;
// code switching out text box and combo box above
try
{
dgvInputs[4, e.RowIndex].Value = Default;
} catch (Exception e2) {
MessageBox.Show(e2.GetType().ToString());
}
L'idea era stata quella di preservare il valore, se possibile, e ho avuto la messagebox per mostrarmi l'eccezione specifica che dovevo prendere, perché non ne ero sicuro. Ma a quanto pare questo incarico non induce immediatamente l'eccezione. Ciò accade solo più tardi, apparentemente durante un altro evento che non sto trattando.
È evidente a posteriori che avrei dovuto includere questo codice nel campione. Non ho idea di come l'ho trascurato. Le mie scuse a tutti ho guidato un inseguimento selvaggio dell'oca lasciando fuori le informazioni critiche. Apprezzo tutta la tua assistenza.
Tipo DBType = (DataType) cb.Value; non si compila –
Ho copiato il codice, corretto alcuni errori di compilazione, eseguito, selezionare entrambi i tipi e immettere o selezionare i valori, non ha fatto apparire alcun messaggio di errore. –
@LeiYang - Ho severamente troncato il codice per l'esempio e ho provato a cambiare "DBType" in "DataType" perché c'è un "DbType" in una libreria di riserva (che ho scoperto solo dopo aver scelto il mio nome) e non l'ho fatto Voglio confonderci. Dovrò provare l'esempio troncato qui me stesso. Anche se ho provato a non farlo, potrei aver rimosso qualcosa di rilevante. –