In C# .NET 2.0, ho un ComboBox WinForms con DropDownList di ComboBoxStyle. Tuttavia, il menu a discesa viene visualizzato ogni volta che l'utente fa clic in qualsiasi punto della casella combinata. Invece, mi piacerebbe averlo aperto solo quando l'utente fa clic esplicitamente sul pulsante a discesa. Quando l'utente fa clic sul resto della casella combinata, desidero semplicemente assegnargli il focus della tastiera in modo che lui o lei possano utilizzare alcuni comandi da tastiera sull'elemento selezionato. Qual'è il miglior modo per farlo?Come posso forzare l'apertura di un ComboBox di DropDownList solo quando l'utente fa clic sul pulsante a discesa?
risposta
Dopo qualche aiuto da parte delle altre risposte, sono arrivato a questa soluzione rapida:
public class MyComboBox : ComboBox
{
public MyComboBox()
{
FlatStyle = FlatStyle.Popup;
DropDownStyle = ComboBoxStyle.DropDownList;
}
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x0201 /* WM_LBUTTONDOWN */ || m.Msg == 0x0203 /* WM_LBUTTONDBLCLK */)
{
int x = m.LParam.ToInt32() & 0xFFFF;
if (x >= Width - SystemInformation.VerticalScrollBarWidth)
base.WndProc(ref m);
else
{
Focus();
Invalidate();
}
}
else
base.WndProc(ref m);
}
}
Si può essere in grado di ottenere la posizione X, Y del clic del mouse e da lì si può forzare il collasso se non è presente nella "icona" a discesa (per mancanza di una parola migliore).
Hai due problemi da considerare. Il primo è piuttosto semplice: determina se il menu a discesa deve essere aperto o chiuso. Questo codice può farlo:
void comboBox1_MouseClick(object sender, MouseEventArgs e)
{
ComboBox combo = sender as ComboBox;
int left = combo.Width - (SystemInformation.HorizontalScrollBarThumbWidth + SystemInformation.HorizontalResizeBorderThickness);
if (e.X >= left)
{
// They did click the button, so let it happen.
}
else
{
// They didn't click the button, so prevent the dropdown.
}
}
La seconda questione è più significativo - in realtà impedendo la discesa di apparire. L'approccio più semplice è:
comboBox1.DropDownStyle = ComboBoxStyle.DropDown;
Tuttavia, ciò consente di digitare nella casella, che potrebbe non essere desiderato.
Ho trascorso circa 15 minuti a esaminare le opzioni e sembra che per evitare che il menu a discesa venga visualizzato e impedire allo stesso tempo all'utente di digitare nel menu a discesa, è necessario creare una sottoclasse del controllo. In questo modo, puoi ignorare OnMouseClick() e chiamare solo base.OnMouseClick() quando hanno fatto clic sul pulsante. Sarebbe simile a questa (non testata):
public class CustomComboBox : ComboBox
{
protected override void OnMouseClick(MouseEventArgs e)
{
base.OnMouseClick(e);
int left = this.Width - (SystemInformation.HorizontalScrollBarThumbWidth + SystemInformation.HorizontalResizeBorderThickness);
if (e.X >= left)
{
// They did click the button, so let it happen.
base.OnMouseClick(e);
}
else
{
// They didn't click the button, so prevent the dropdown.
// Just do nothing.
}
}
}
La larghezza della barra di scorrimento è stato utile, ma utilizzando gli eventi WinForms del mouse/funzioni non è utile. Sono chiamati troppo tardi. – Eric
Gli eventi e le funzioni di WinForm vengono richiamati alla stessa ora dei normali messaggi di Windows. È la gestione di loro che conta. Trovare un modo per prevenire il comportamento predefinito è la sfida, dal momento che i tempi sono gli stessi. –
Stavo scrivendo metaforicamente. Internamente, sembra che prima che gli eventi del mouse di WinForms vengano mai chiamati, viene visualizzato il menu a discesa E viene inviato l'evento a discesa. Pertanto, l'utilizzo degli eventi WinForms non è sufficiente per impedire la visualizzazione dell'elenco a discesa. – Eric