2010-01-04 12 views
11

Diciamo che abbiamo il seguente codice in un'applicazione Windows:ComboBox.SelectedValue non corrisponde visualizzazione del testo quando DropDownStyle = DropDownList in Windows 7

ComboBox comboBox = new ComboBox() 
{ 
    AutoCompleteMode = AutoCompleteMode.SuggestAppend, 
    AutoCompleteSource = AutoCompleteSource.ListItems, 
    DataSource = new string[] { "", "Ark", "Boat", "Bucket" }, 
    DropDownStyle = ComboBoxStyle.DropDownList 
}; 
this.Controls.Add(comboBox); 

TextBox textBox = new TextBox() 
{ 
    Left = comboBox.Right, 
    Top = comboBox.Top, 
    ReadOnly = true 
}; 
textBox.DataBindings.Add("Text", comboBox, "SelectedValue"); 
this.Controls.Add(textBox); 

Niente magia qui, solo un ComboBox legato a una lista di stringhe . Lo TextBox visualizza lo SelectedValue dello ComboBox.

Ho un comportamento imprevisto quando digito "Bucket" nello ComboBox e nella scheda. Per qualche motivo lo ComboBox visualizza "Boat" ma lo TextBox visualizza "Bucket". Mi aspetterei che entrambi mostrino "Bucket".

Si comporta come previsto se cambio lo DropDownStyle in DropDown, ma non voglio che gli utenti siano in grado di digitare tutto ciò che desiderano. Dovrebbero essere in grado di digitare solo gli elementi che sono nella lista.

Ancora più interessante è che, dopo aver digitato "Bucket" e tabulazione, se si digita "Bucket" di nuovo verrà visualizzato "Bucket" in entrambi. Se faccio un terzo tentativo, torna a "Boat" per lo ComboBox e "Bucket" per il "TextBox". Quindi sembra che stia attraversando tutte le B's.

Non l'ho notato fino a quando non ho eseguito l'aggiornamento da XP a Windows 7 di recente. Non vedo come questo possa avere qualcosa a che fare con questo, ma lo sto buttando fuori comunque.

Se questo comportamento è corretto, qualcuno può dirmi cosa dovrei fare per raggiungere il mio comportamento previsto?

UPDATE Sembrerebbe questo è correlato a Windows 7. Tutto si comporta come previsto in Windows XP Mode. Qualcun altro che esegue Windows 7 può provare il mio codice e verificare che non sia pazzo?

+0

Ho preso esattamente il codice e l'ho gettato su una nuova forma e non posso riprodurre il comportamento. Potresti provare a collegare l'evento SelectedIndexChanged e inserire alcuni messaggi della console e vedere cosa sta succedendo mentre digiti nella combo. – TheHurt

+0

Ho aggiunto 'comboBox.SelectedIndexChanged + = new EventHandler (delegato {Console.WriteLine (" SelectedIndex = {0} ", comboBox.SelectedIndex);});' e l'output dice che 'SelectedIndex' è cambiato in" 2 "e quindi a "3", che corrisponde a ciò che mostra il 'TextBox'. – Ecyrb

+0

Se si tratta di un bug riproducibile, è necessario inviarlo a Microsoft Connect all'indirizzo: https://connect.microsoft.com/VisualStudio/ –

risposta

2

Questo hotfix risolverà questo problema.

+2

Sebbene questo collegamento possa rispondere alla domanda, è meglio includere qui le parti essenziali della risposta e fornire il link per riferimento. Le risposte di solo collegamento possono diventare non valide se la pagina collegata cambia. –

+1

Bene, questo è il collegamento alla pagina di download dell'aggiornamento rapido che Microsoft ha spedito.Non c'è molto da aggiungere qui e non mi aspetto che questo link scada :) – bittusarkar

6

Una soluzione potrebbe essere cambiando il DropDownStyle-DropDown e aggiungendo il seguente:

comboBox.Validating += new CancelEventHandler((o, e) => 
    { 
     e.Cancel = (comboBox.DataSource as string[]).Contains(comboBox.Text) == false; 
    }); 

che permetterà agli utenti di digitare qualsiasi cosa, ma non permetterà loro di scheda lontano dal controllo a meno hanno digitato una valida articolo.

Eppure, non è soddisfatto del comportamento passaggio da XP a Win 7.

+1

+1 Ecco la versione di vb.net che ha funzionato per me: 'e.Cancel = Not (comboBox.Items.Contains (comboBox.Text))'. –

0

So che questa risposta è abbastanza vecchio, ma mi è stato che richiedono una risposta a questo Windows 7 bug. Ho armeggiato per un po 'nella vena di Ecyrb e si avvicinò con la seguente work-around:

Da initForm() per l'applicazione Aggiungi questa proprietà:

Me.KeyPreview = True 

Dal punto in cui è situato l'ComboBox:

Private mbTab As Boolean 
Private miPrevIndex As Integer = -1 
Private Sub DropDownListEx_Validating(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles Me.Validating 
    miPrevIndex = Me.SelectedIndex 
    MyBase.OnSelectedIndexChanged(e) 
End Sub 
Private Sub DropDownListEx_PreviewKeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.PreviewKeyDownEventArgs) Handles Me.PreviewKeyDown 
    mbTab = e.KeyCode = Windows.Forms.Keys.Tab 
End Sub 
Protected Overrides Sub OnDropDownClosed(ByVal e As System.EventArgs) 
    MyBase.OnDropDownClosed(e) 
    If Me.SelectedIndex <> miPrevIndex Then 
     If mbTab = True Then 
      Me.SelectedIndex = miPrevIndex 
     Else 
      miPrevIndex = Me.SelectedIndex 
     End If 
     MyBase.OnSelectedIndexChanged(e) 
    End If 
End Sub 

Ora, nel mio esempio, sto usando un controllo personalizzato che eredita comboBox. Quindi dovrai collegarli per uso personale.

0

Ignorare il metodo OnTextChanged e non passare il messaggio alla base.

protected override void OnTextChanged(EventArgs e) 
{ 
    //Eat the message so it doesn't select an incorrect value. 
} 
1

Mi sono imbattuto in questo io stesso e ho trovato alcuni soluzioni alternative. Alla fine ho arrotolato la mia soluzione come una sottoclasse ComboBox:

//as noted here: https://connect.microsoft.com/VisualStudio/feedback/details/523272/combobox-does-not-display-selectedvalue-to-user-in-windows-7 
//Windows 7 has issues with ComboBoxStyle.DropDownList mixed with AutoCompleteMode.Append or AutoCompleteMode.SuggestAppend 
//this class seeks to address those problems 
public class BetterComboBox : ComboBox 
{ 
    private int _windows7CorrectedSelectedIndex = -1; 

    private int? _selectedIndexWhenDroppedDown = null; 
    protected override void OnDropDown(EventArgs e) 
    { 
    _selectedIndexWhenDroppedDown = SelectedIndex; 
    base.OnDropDown(e); 
    } 
    private bool _onDropDownClosedProcessing = false; 
    protected override void OnDropDownClosed(EventArgs e) 
    { 
    if (_selectedIndexWhenDroppedDown != null && _selectedIndexWhenDroppedDown != SelectedIndex) 
    { 
     try 
     { 
     _onDropDownClosedProcessing = true; 
     OnSelectionChangeCommitted(e); 
     } 
     finally 
     { 
     _onDropDownClosedProcessing = false; 
     } 
    } 
    base.OnDropDownClosed(e); 
    if (SelectedIndex != _windows7CorrectedSelectedIndex) 
    { 
     SelectedIndex = _windows7CorrectedSelectedIndex; 
     OnSelectionChangeCommitted(e); 
    } 
    } 
    protected override void OnSelectionChangeCommitted(EventArgs e) 
    { 
    if (!_onDropDownClosedProcessing) _windows7CorrectedSelectedIndex = SelectedIndex; 
    _selectedIndexWhenDroppedDown = null; 
    base.OnSelectionChangeCommitted(e); 
    } 
    protected override void OnSelectedIndexChanged(EventArgs e) 
    { 
    bool alreadyMatched = true; 
    if (_windows7CorrectedSelectedIndex != SelectedIndex) 
    { 
     _windows7CorrectedSelectedIndex = SelectedIndex; 
     alreadyMatched = false; 
    } 
    base.OnSelectedIndexChanged(e); 

    //when not dropped down, the SelectionChangeCommitted event does not fire upon non-arrow keystrokes due (I suppose) to AutoComplete behavior 
    //this is not acceptable for my needs, and so I have come up with the best way to determine when to raise the event, without causing duplication of the event (alreadyMatched) 
    //and without causing the event to fire when programmatic changes cause SelectedIndexChanged to be raised (_processingKeyEventArgs implies user-caused) 
    if (!DroppedDown && !alreadyMatched && _processingKeyEventArgs) OnSelectionChangeCommitted(e); 
    } 
    private bool _processingKeyEventArgs = false; 
    protected override bool ProcessKeyEventArgs(ref Message m) 
    { 
    try 
    { 
     _processingKeyEventArgs = true; 
     return base.ProcessKeyEventArgs(ref m); 
    } 
    finally 
    { 
     _processingKeyEventArgs = false; 
    } 
    } 
} 
1

Ho creato la mia soluzione perché non pensavo che la distribuzione di un hotfix a tutti i computer degli utenti fosse ragionevole o gestibile. Tuttavia la descrizione del problema di hotfix descrive il mio problema. Vedi l'elenco qui di seguito, ad esempio:

Acorn di Apple
Bad
Bed
Brick
formaggio

Se sto selezionando una voce inizia con B come il letto, sarebbe selezionare la prima volta a partire con B che sarebbe cattivo. Questo è se scrivo solo i primi due caratteri Be (non ho provato a digitare un'intera stringa come nel mio caso reale, sarebbe irragionevole per un utente farlo).

Ho un ComboBox con le seguenti impostazioni:
AutoCompleteMode - SuggestAppend,
AutoCompleteSource - ListItems,
DropDownStyle - DropDownList.

Per risolvere il problema, ho fatto quanto segue poiché ho notato che il mio valore desiderato è stato selezionato durante l'evento SelectedIndexChanged ma non l'evento Leave.

int myDesiredIndexSelection; 

    private void myComboBox_SelectedIndexChanged(object sender, EventArgs e) 
    { 
     myDesiredIndexSelection = myComboBox.SelectedIndex; 
    } 

    private void myComboBox_Leave(object sender, EventArgs e) 
    { 
     myComboBox.SelectedIndex = myDesiredIndexSelection; 
    } 
    private void myForm_KeyUp(object sender, KeyEventArgs e) 
    { 
     if (e.KeyCode == Keys.Tab) 
      myComboBox.SelectedIndex = myDesiredIndexSelection; 
    } 

L'evento Leave sembra rispondere al tasto Invio. KeyUp (KeyDown non ha funzionato) sembrava risolvere il problema della scheda.

0

Posso ancora riprodurre questo su Windows 10, quindi ho pensato di aggiungere la mia soluzione alla lista.

Private Sub LeaveComboBox(s As Object, e As EventArgs) Handles ComboBox1.Leave 
    Dim sender as ComboBox = DirectCast(s, ComboBox) 

    If sender.DroppedDown Then 
     ' Save the correct item 
     Dim correctSelection as Object = sender.SelectedItem 

     ' The core of the issue seems to be that while searching, Leave is 
     ' triggered before DropDownClosed when you hit the TAB. 
     ' Instead, trigger that now: 
     sender.DroppedDown = False 

     ' Restore the correct item. 
     sender.SelectedItem = correctSelection 
    End If 
End Sub