2009-04-15 18 views

risposta

4

Ignorare l'evento SelectionChanged è l'approccio giusto. La proprietà CurrentCell può essere utilizzata per impostare la cella corrente. Volete qualcosa di simile:

private void dataGridView_SelectionChanged(object sender, EventArgs e) 
{ 
    DataGridViewCell currentCell = dataGridView.CurrentCell; 
    if (currentCell != null) 
    { 
     int nextRow = currentCell.RowIndex; 
     int nextCol = currentCell.ColumnIndex + 1; 
     if (nextCol == dataGridView.ColumnCount) 
     { 
      nextCol = 0; 
      nextRow++; 
     } 
     if (nextRow == dataGridView.RowCount) 
     { 
      nextRow = 0; 
     } 
     DataGridViewCell nextCell = dataGridView.Rows[nextRow].Cells[nextCol]; 
     if (nextCell != null && nextCell.Visible) 
     { 
      dataGridView.CurrentCell = nextCell; 
     } 
    } 
} 

Avrai bisogno di aggiungere un test per la cella attiva in fase di sola lettura e ciclo mentre la cella successiva è invisibile o di sola lettura. Dovrai inoltre verificare di non eseguire mai il loop per sempre se tutte le celle sono di sola lettura.

Dovrai affrontare il caso in cui l'indice di visualizzazione è diverso anche dall'indice di base.

Per ottenere questo comportamento solo quando si preme Tab è necessario aggiungere un gestore KeyDown:

private void AlbumChecker_KeyDown(object sender, KeyEventArgs e) 
{ 
    if (e.KeyCode == Keys.Tab) 
    { 
     SelectNextEditableCell(DataGridView dataGridView); 
    } 
} 

e mettere il primo codice in questo nuovo metodo.

È possibile controllare che anche DataGridView sia attivo.

+0

ma voglio questo comportamento solo quando si preme il tasto 'TAB' non quando si usa il mouse anche – Cornel

+2

l'ultimo non funzionerà quando la cella è in modalità di modifica :( – Cornel

+0

@Cornel - non so cosa suggerire realmente. Che comportamento vedi? mi sta leggendo di più sui metodi DataGridView nella documentazione MSDN. Potrebbe richiedere un po 'di scavo, ma di solito le informazioni sono lì. – ChrisF

0

Eredita DataGridView e override ProcessDialogKey (per il tasto premuto durante la modifica) e ProcessDataGridViewKey (per il tasto premuto mentre non viene modificato). Quando è stato premuto Tab, impostare CurrentCell sulla successiva cella non di sola lettura.

Sovrascrivere facoltativamente WndProc per filtrare i clic del mouse su celle di sola lettura. (Vedi DataGridView.GetColumnDisplayRectangle per trovare su quale colonna è stato fatto clic).

Buona fonte di avvio da here.

0

Quando la cella è in modalità di modifica, e si desidera ascoltare eventi di battitura, si potrebbe provare la gestione degli eventi EditingControlShowing del DataGridView ...

Private Sub myDvGrid_EditingControlShowing(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewEditingControlShowingEventArgs) Handles myDvGrid.EditingControlShowing 
    Dim c As DataGridViewTextBoxEditingControl = DirectCast(e.Control, DataGridViewTextBoxEditingControl) 

    RemoveHandler c.PreviewKeyDown, AddressOf edtctrlOn_PreviewKeyDown 
    RemoveHandler c.TextChanged, AddressOf edtctrlOn_TextChanged 

    AddHandler c.TextChanged, AddressOf edtctrlOn_TextChanged 
    AddHandler c.PreviewKeyDown, AddressOf edtctrlOn_PreviewKeyDown 

End Sub 

Poi, in caso edtctrlOn_PreviewKeyDown, è possibile bolla la argomenti al gestore di eventi PreviewKeyDown del datagrid originale.

3

Ho fatto un esempio ereditando la classe DataGridView. L'esempio funziona per i tasti TAB e INVIO in modo che l'utente possa inserire rapidamente i dati, ma può comunque utilizzare il mouse oi tasti su, giù, destra, sinistra per selezionare le celle e copiarle su un excel. Funziona simulando diverse TAB fino a quando la Grid non raggiunge una cella ReadOnly. Spero sia utile

using System; 
using System.Collections.Generic; 
using System.Text; 
using System.Windows.Forms; 

namespace System.Windows.Forms 
{ 
    class MyDataGridView : DataGridView 
    { 
    protected override bool ProcessDialogKey(Keys keyData) 
    { 
     if (keyData == Keys.Enter || keyData == Keys.Tab) 
     { 
     MyProcessTabKey(Keys.Tab); 
     return true; 
     } 
     return base.ProcessDialogKey(keyData); 
    } 

    protected override bool ProcessDataGridViewKey(KeyEventArgs e) 
    { 
     if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Tab) 
     { 
     MyProcessTabKey(Keys.Tab); 
     return true; 
     } 
     return base.ProcessDataGridViewKey(e); 
    } 

    protected bool MyProcessTabKey(Keys keyData) 
    { 
     bool retValue = base.ProcessTabKey(Keys.Tab); 
     while (this.CurrentCell.ReadOnly) 
     { 
     retValue = base.ProcessTabKey(Keys.Tab); 
     } 
     return retValue; 
    } 
    } 
} 
11
private void dataGridView1_CellEnter(object sender, DataGridViewCellEventArgs e) 
{ 
    if (dataGridView1.CurrentRow.Cells[e.ColumnIndex].ReadOnly) 
    { 
     SendKeys.Send("{tab}"); 
    } 
} 
+0

Questa è di gran lunga la soluzione più semplice. Ho anche aggiunto un passaggio per impostare Selected = False sulla cella prima che SendKeys cancelli l'artefatto visivo sull'ultima cella selezionata nella griglia prima che la griglia venga estratta. Un posto in cui so dove c'è un problema minore è se AllowUserToDeleteRows = True. La soluzione alternativa è impostare SelectionMode = FullRowSelect, non perfetto visivamente ma piuttosto buono. Grazie – Jay13

0

Hector - Spero che si sta ancora ascoltando. La tua soluzione è la più elegante e semplice che ho visto nella ricerca estesa. Ho trovato il suggerimento di ignorare gli eventi chiave, ma il tuo suggerimento di invocare base.ProcessTabKey è particolarmente semplice e gestisce lo spostamento passando al controllo successivo quando raggiungi la fine del dgv. L'unica cosa aggiuntiva di cui la tua soluzione aveva bisogno era un controllo in MyProcessTabKey per l'ultima cella del dgv. Se quella cella è in sola lettura e le schede utente nella cella precedente, l'istruzione while entra in un ciclo infinito. Aggiungere il codice seguente come prima istruzione nel ciclo while sembra risolvere il problema, anche se lascia l'ultima cella (di sola lettura) la cella "attiva" (il che significa che appare come se fosse selezionata).

if (this.CurrentCell.RowIndex == this.Rows.Count - 1 
       && this.CurrentCell.ColumnIndex == this.Columns.Count - 1) 
       { retValue = false; break; } 

Ho una domanda di follow-on. Tu o qualcun altro sai come far funzionare questo approccio con Shift-Tab, quindi il dgv salta anche le celle di sola lettura in una direzione all'indietro? Poiché Shift e Tab sono diversi eventi chiave, non so come rilevare Shift-Tab nei metodi ProcessDialogKey e ProcessDataGridViewKey sottoposti a override. Grazie. Steve

0

È possibile prendere tasto Tab da questo codice nella ProcessDialogKey

Dim uKeyCode As Keys = (keyData And Keys.KeyCode) 
    Dim uModifiers As Keys = (keyData And Keys.Modifiers) 

    (uKeyCode = Keys.Return OrElse uKeyCode = Keys.Tab) AndAlso uModifiers = Keys.Shift 

E da questo codice nella ProcessDataGridViewKey

(e.KeyCode = Keys.Return OrElse e.KeyCode = Keys.Tab) AndAlso e.Modifiers = Keys.Shift 
-1
if (e.KeyValue == 13) 
     { 
      e = new KeyEventArgs(Keys.Tab); 
     } 
+0

Si prega di prendere in considerazione l'inclusione di alcune informazioni sulla risposta, piuttosto che il semplice inserimento del codice. Cerchiamo di fornire non solo "correzioni", ma aiutare le persone a imparare. Dovresti spiegare cosa c'era di sbagliato nel codice originale, cosa hai fatto in modo diverso e perché le tue modifiche hanno funzionato. –

Problemi correlati