C#&.Net 2.0の質問(WinForms)
ComboBox
にアイテムのセットがあり、それらのいずれも選択されていません。この状況では、コンボ「項目を選択してください」に文字列を表示したいと思います。
現在の実装では、インデックスにそのようなテキストを含む空のアイテムが追加され、ユーザーが次のアイテムのいずれかを選択すると削除されます。残念ながら、空のアイテムもドロップダウンリストに表示されます。この状況を回避する方法など-アイテムが選択されていないときにComboBox
にカスタムテキストを表示する方法はありますか?
以下の回答は、ComboBoxStyle
がDropDown
に設定されている場合に機能します(ComboBox
は編集可能です)。 ComboBoxStyle
がDropDownList
に設定されているときにこれを行う可能性はありますか?
ここでは、pavlo_uaによって作成されたソリューションを見つけることができます: 。Net> 2.0 がある場合と 。Net =がある場合= 2.0(pavlo_ua回答の検索)
乾杯、jbk
編集:だからリンクだけでなく明確な答えを得るために
スタイルがDropDownに設定されている場合(および編集可能)に、コンボボックスのテキストを設定できます。 .Netバージョン<3.0の場合、IsReadonlyプロパティがないため、win apiを使用してcomboboxのテキストボックスを読み取り専用に設定する必要があります。
private bool m_readOnly = false;
private const int EM_SETREADONLY = 0x00CF;
internal delegate bool EnumChildWindowsCallBack( IntPtr hwnd, IntPtr lParam );
[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
[ DllImport( "user32.dll" ) ]
internal static extern int EnumChildWindows( IntPtr hWndParent, EnumChildWindowsCallBack lpEnumFunc, IntPtr lParam );
private bool EnumChildWindowsCallBackFunction(IntPtr hWnd, IntPtr lparam)
{
if( hWnd != IntPtr.Zero )
{
IntPtr readonlyValue = ( m_readOnly ) ? new IntPtr( 1 ) : IntPtr.Zero;
SendMessage( hWnd, EM_SETREADONLY, readonlyValue, IntPtr.Zero );
comboBox1.Invalidate();
return true;
}
return false;
}
private void MakeComboBoxReadOnly( bool readOnly )
{
m_readOnly = readOnly;
EnumChildWindowsCallBack callBack = new EnumChildWindowsCallBack(this.EnumChildWindowsCallBackFunction );
EnumChildWindows( comboBox1.Handle, callBack, IntPtr.Zero );
}
コンボボックスの挿入メソッドを使用して、「インデックスを0に選択してください」という項目を挿入し、
comboBox1.Items.Insert(0, "Please select any value");
すべてのアイテムを最初のインデックスの後にコンボボックスに追加します。フォームロードセット内
comboBox1.SelectedIndex = 0;
編集:
フォームの読み込みでは、ハードコーディングによりcomboBox1.Text
にテキストを書き込みます
comboBox1.Text = "Please, select any value";
そして、comboBox1のTextChangedイベントに次のコードを記述します
private void comboBox1_TextChanged(object sender, EventArgs e)
{
if (comboBox1.SelectedIndex < 0)
{
comboBox1.Text = "Please, select any value";
}
else
{
comboBox1.Text = comboBox1.SelectedText;
}
}
ここに私がそれをする方法があります。それは最良の方法ではないかもしれず、最小限の制御を提供します。ただし、それは簡単で迅速であり、他のユーザーがより多くのオプションを使用できるように共有することをお勧めします。
<ComboBox SelectedIndex="0">
<ComboBoxItem Visibility="Collapsed">Please select one...</ComboBoxItem>
<ComboBoxItem>1</ComboBoxItem>
<ComboBoxItem>2</ComboBoxItem>
<ComboBoxItem>3</ComboBoxItem>
<ComboBoxItem>4</ComboBoxItem>
</ComboBox>
この背後にある考え方は、最初の選択はインデックス0であり、これは折りたたまれているため、ユーザーが他の何かを選択すると選択の下で使用できないことです。欠点は、選択したインデックスをチェックしている場合、インデックス0は選択が行われなかったことを意味することに注意する必要があることです。
private void comboBox1_TextChanged(object sender, EventArgs e)
{
if (comboBox1.Text == "")
comboBox1.Text = "Select one of the answers";
}
コンボボックスでアイテムを選択すると、この行が存在する起動時にトリックを行う必要があり、このアイテムのテキストが表示されます。テキストを削除すると、このテキストが再び表示されます
私はそれを行うためのネイティブの.NETの方法を見ることができませんが、基礎となるWin32コントロールで手を汚したい場合...
内部エディットコントロールのハンドルを含むCOMBOBOXINFO
構造を持つCB_GETCOMBOBOXINFO
メッセージを送信できるはずです。その後、エディットコントロールに、文字列へのポインタを含むEM_SETCUEBANNER
メッセージを送信できます。 (これには少なくともXPおよび視覚スタイルを有効にする必要があることに注意してください。
DropDownListスタイルを維持できるように、簡単な回避策を使用しました。
class DummyComboBoxItem
{
public string DisplayName
{
get
{
return "Make a selection ...";
}
}
}
public partial class mainForm : Form
{
private DummyComboBoxItem placeholder = new DummyComboBoxItem();
public mainForm()
{
InitializeComponent();
myComboBox.DisplayMember = "DisplayName";
myComboBox.Items.Add(placeholder);
foreach(object o in Objects)
{
myComboBox.Items.Add(o);
}
myComboBox.SelectedItem = placeholder;
}
private void myComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
if (myComboBox.SelectedItem == null) return;
if (myComboBox.SelectedItem == placeholder) return;
/*
do your stuff
*/
myComboBox.Items.Add(placeholder);
myComboBox.SelectedItem = placeholder;
}
private void myComboBox_DropDown(object sender, EventArgs e)
{
myComboBox.Items.Remove(placeholder);
}
private void myComboBox_Leave(object sender, EventArgs e)
{
//this covers user aborting the selection (by clicking away or choosing the system null drop down option)
//The control may not immedietly change, but if the user clicks anywhere else it will reset
if(myComboBox.SelectedItem != placeholder)
{
if(!myComboBox.Items.Contains(placeholder)) myComboBox.Items.Add(placeholder);
myComboBox.SelectedItem = placeholder;
}
}
}
データバインディングを使用する場合、バインドする型のダミーバージョンを作成する必要があります-永続ロジックの前に削除することを確認してください。
フォームInitializeComponent();
の後の1行
cbo_MyDropBox.Text = "Select a server...";
必要なのは一度だけですか?選択が必須の場合に必要なことは、ボックスインデックス!= -1
。他の回答がこれを実現するためにフープを飛び越える理由を詳しく説明できますか?
ここで不足しているのは、この最初のテキストだけがグレー表示されていることです。本当に必要な場合は、前のラベルを使用して、インデックスが変更されたらオフにします。
以下のように、コンボボックスのDropdownstyleプロパティをDropdownに設定し、コンボボックステキストを「選択」に設定します。
combobox.DataSource = dsIn.Tables[0];
combobox.DisplayMember = "Name";
combobox.ValueMember = "Value";
combobox.Text = "--Select--";
ComboBoxStyle
がDropDownList
に設定されている場合、ユーザーがアイテムを選択したことを確認する最も簡単な方法は、SelectedIndex = -1
、空になります
これはDropDownListスタイルで動作します-ComboBoxから派生したクラスを作成します
(再構築後にツールボックスに表示されます)System.Drawingを使用してヒントを描画します。
このコントロールをツールボックスからフォームに配置し、そのプロパティにヒント「アイテムを選択してください」を設定します。
public class HintComboBox : ComboBox
{
string hint;
public string Hint
{
get { return hint; }
set { hint = value; Invalidate(); }
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == 0xf && !Focused && string.IsNullOrEmpty(Text) && !string.IsNullOrEmpty(Hint))
using (var g = CreateGraphics())
{
TextRenderer.DrawText(g, Hint, Font, ClientRectangle, SystemColors.GrayText, BackColor,
TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter);
}
}
}
私はこれが古いスレッドであることを認識していますが、この質問に対する答えを検索するかもしれない他の人に、現在のバージョンのVisual Studio(2015)には、元々jotbek尋ねた。 [共通]プロパティの下の[プロパティ]ボックスを使用します。
以前のソリューションのどれもあなたのために働いていない場合、コンボボックスにいくつかの検証を追加してみませんか?
var orginalindex = 0;
private void comboBox1_SelectedItemChanged(object sender, EventArgs e)
{
if (comboBox1.SelectedIndex == 0)
{
comboBox1.Text = "Select one of the answers";
comboBox1.SelectedIndex = comboBox1.SelectedIndex;
}
else
{
orginalindex = comboBox1.SelectedIndex;
}
}
私もこれに対する解決策を見つけたいと思っていました。これは古い投稿であることがわかりますが、私のアプローチが他の誰かのためにこの問題を単純化することを望んでいます。
DropDownListのドロップダウンスタイルのコンボボックスを使用していましたが、これは他のスタイルでも機能するはずです。私の場合、テキストを「Select Source」と読み、他のオプションを「File」と「Folder」にする必要がありました。
comboBox1.Items.AddRange(new string[] {"Select Source", "File", "Folder" });
comboBox1.Text = "Select Source";
必要に応じて、代わりに0インデックスを選択できます。次に、テキストが表示されていても問題ではないため、インデックスが変更されたときに「ソースを選択」項目を削除しました。
comboBox1.SelectedIndexChanged += new EventHandler(comboBox1_IndexChanged);
private void comboBox1_IndexChanged(object sender, EventArgs e)
{
comboBox1.Items.Remove("Select Source");
if (comboBox1.SelectedIndex != -1)
{
if (comboBox1.SelectedIndex == 0) // File
{
// Do things
}
else if (comboBox1.SelectedIndex == 1) // Folder
{
// Do things
}
}
}
ありがとう
@Andrei Karcheuskiの動作するアプローチを得ることができませんでしたが、彼はこのアプローチに私をインスパイアしました:
public partial class HintComboBox : ComboBox
{
string hint;
Font greyFont;
[Localizable(true)]
public string Hint
{
get { return hint; }
set { hint = value; Invalidate(); }
}
public HintComboBox()
{
InitializeComponent();
}
protected override void OnCreateControl()
{
base.OnCreateControl();
if (string.IsNullOrEmpty(Text))
{
this.ForeColor = SystemColors.GrayText;
Text = Hint;
}
else
{
this.ForeColor = Color.Black;
}
}
private void HintComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
if( string.IsNullOrEmpty(Text) )
{
this.ForeColor = SystemColors.GrayText;
Text = Hint;
}
else
{
this.ForeColor = Color.Black;
}
}
残念なことに、上記のどれも私のために機能しなかったので、代わりに「選択してください」というラベルをcomboxboxの上に追加しました。次のコードを使用して、表示と非表示を切り替えました。
コンボボックスを初期化するときに、選択した値がない場合は、それを前面に移動してテキストを設定します。
PleaseSelectValueLabel.BringToFront();
PleaseSelectValueLabel.Text = Constants.AssessmentValuePrompt;
選択された値がある場合、私はそれを後ろに送ります:
PleaseSelectValueLabel.SendToBack();
次に、ユーザーが値を選択したかどうかに応じて、次のイベントを使用してラベルを前面または背面に移動します。
private void PleaseSelectValueLabel_Click(object sender, EventArgs e)
{
PleaseSelectValueLabel.SendToBack();
AssessmentValue.Focus();
}
private void AssessmentValue_Click(object sender, EventArgs e)
{
PleaseSelectValueLabel.SendToBack();
}
//if the user hasnt selected an item, make the please select label visible again
private void AssessmentValue_Leave(object sender, EventArgs e)
{
if (AssessmentValue.SelectedIndex < 0)
{
PleaseSelectValueLabel.BringToFront();
}
}