2013-07-24 5 views
5

Avrei bisogno di un evento che si attiva quando verrà modificata la riga corrente di System.Windows.Forms.DataGridView e che consente di annullare questa modifica, ad es. impostando la proprietà Cancel di EventArgs su true.Evento per impedire a C# DataGridView di modificare la riga corrente

Conosco lo CurrentCellChanged (la riga è già cambiata quando viene chiamato l'evento) e gli eventi RowLeave (nessuna possibilità di annullare l'operazione), ma non forniscono ciò che mi servirebbe. Ho anche provato a utilizzare l'evento RowValidating, ma questo evento viene anche chiamato quando la riga viene appena convalidata (senza l'intenzione di lasciarla), ad esempio quando chiamo <ParentForm>.Validate(), che porta a molte confusioni.

C'è qualche altra possibilità o una soluzione pulita (er) per ottenere il comportamento desiderato?

+0

se non si desidera che all'utente di cambiare qualche cosa usare CellEndEdit? Se si desidera impedire all'utente di modificare qualcosa impostato readonly = true – Ehsan

+0

A seconda di quando si desidera impedire un tipo di input, l'impostazione dell'evento KeyPress Handled = true bloccherà un carattere o un formato non valido dei caratteri. - Inoltre, non fa distinzione tra celle diverse, quindi dovrai testare quale colonna o riga è stata modificata per il tuo test corretto. –

+0

Puoi ampliare ciò che vuoi raggiungere? – CristisS

risposta

0

Dopo aver provato un sacco di cose diverse sono giunto alla soluzione che la soluzione più semplice e (per me) migliore sarebbe quella di controllare quale controllo è focalizzato nell'evento RowValidating dello DataGridView. Questa soluzione risolve esattamente il problema che ho riscontrato: l'evento RowValidating è stato lanciato facendo clic su altri pulsanti, ad esempio. Esistono ancora casi speciali che causano l'evento RowValidating anche se la riga corrente non cambia (ordinando lo DataGridView facendo clic sull'intestazione di una colonna, ad esempio) ma penso di poter vivere con questi problemi minori. Forse una versione futura di .NET implementerà un DataGridView con un evento RowLeaving che può essere annullato.

1

Penso che l'opzione migliore sia utilizzare RowValidating con una condizione bool per verificare se si chiama .Validate().

EDIT

Per il tuo ultimo commento, perché non aggiungere un controllo per dataGridView.IsCurrentRowDirty? Per esempio:

private void dataGridView1_RowValidating(object sender, DataGridViewCellCancelEventArgs e) { 
    if (dataGridView1.IsCurrentRowDirty) { 
     if (dataCheck()) 
      if (MessageBox.Show("Ok?", "Save?", MessageBoxButtons.YesNoCancel) == DialogResult.Cancel) { 
       e.Cancel = true; 
      } 
    } 
} 

Se non ci sono dati sporchi, non importa chi chiama la convalida del dataCheck non sarà reso e non apparirà la messageBox.

EDIT

è possibile sostituire il 'se' clausole con alcun controllo che si desidera, tra cui una per dataGridView2.

È anche possibile estendere il controllo dataGridView se si hanno requisiti molto complicati.

EDIT

Ora capisco la vostra esigenza. Non penso che esista una soluzione rapida e pulita. Vorrei utilizzare l'evento SelectionChanged e impostare la logica per impedire la modifica. Qualcosa di simile:

//rember the selection of the index 
private int _currentIndex; 
private bool _rollingBackSelection; 

private void SelectionChanged(...){ 
    //when changing back to the selection in dgv1 prevent dgv2 check 
    if (_rollingBackSelection) { 
     _rollingBackSelection = false; 
     return; 
    } 
    if (dgv2IsDirty()) { 
      var result = MessageBox.Show("Ok?", "Save?", MessageBoxButtons.YesNoCancel); 
      if (result == DialogResult.Cancel) { 
      _rollingBackSelection = true; 
      //rollback to the previous index 
      dgv1.Rows[_currentIndex].Selected = true; 
      return; 
      } 
      if (result == DialogResult.Yes) 
      dgv2Save(); 
     dgv2Load(); 
     _currentIndex = dgv1.SelectedRows[0].Index; 
    } 
} 

Penso che qualcosa come sopra sia la soluzione migliore.

+0

La cosa brutta è che l'evento RowValidating non viene chiamato solo dal metodo Validate(). Viene anche chiamato ad esempio se clicco su un pulsante. Questo è quello che intendevo quando ho detto che questo porta a molte confusioni. – Peter

+0

Non potresti impostare un bool quando mostri il MessageBox e lo usi nella RowValidating? Inoltre, quale evento stai usando per controllare il datatable sottostante e mostrare il MessageBox, suppongo si tratti di un evento datagriview? – CristisS

+0

Siamo spiacenti, ma non capisco il motivo per cui imposta un bool quando mostra MessageBox. Attualmente utilizzo l'evento RowValidating per verificare le modifiche (metodo DataTable.GetChanges()) e infine mostrare la messagebox, come indicato sopra nella mia domanda. Ma questa è la cosa che sto chiedendo, quale evento utilizzare per rilevare e prevenire i cambiamenti di riga. – Peter

1

Appena analizzato in un problema simile e dopo molti tentativi il mio unico intervento era usare "Invio e partenza" per sapere quando il modulo era NotActive per evitare la convalida - Fortunatamente l'ordine di attivazione era prima degli eventi di livello riga

HTH - Mike

private bool IsActive = false; 

    private void dgbList_RowValidating(object sender, DataGridViewCellCancelEventArgs e) 
    { 
     if (IsActive) 
     { 
      if (Do_I_NeedTo_Cancel) 
       e.Cancel = true; 
     } 
    } 

    private void dgList_Leave(object sender, EventArgs e) 
    { 
     IsActive = false; 
    } 

    private void dgList_Enter(object sender, EventArgs e) 
    { 
     IsActive = true; 
    } 
Problemi correlati