web-dev-qa-db-ja.com

「ここに入力」と表示されるTextBoxを実装するにはどうすればよいですか?

ユーザーがTextBoxにテキストを入力するまで「ここに入力...」を表示することは、最近ではよく知られているユーザビリティ機能です。この機能をC#でどのように実装しますか?

私のアイデアはOnTextChangedをオーバーライドすることですが、「Type here」との間でテキストの変更を処理するロジックは少し難しいです...

初期化時に「Type here」を表示し、最初の入力で削除するのは簡単ですが、入力したテキストが空になるたびにメッセージを表示したいと思います。

37
mafu

探しているのは、「watermark」の付いたTextBoxです。

C# here のサンプル実装があります。すべてのクレジットはWael Alghoolにあります。

彼のコードの関連部分は次のとおりです。

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

namespace wmgCMS
{
    class WaterMarkTextBox : TextBox
    {
        private Font oldFont = null;
        private Boolean waterMarkTextEnabled = false;

        #region Attributes 
            private Color _waterMarkColor = Color.Gray;
            public Color WaterMarkColor
            {
                get { return _waterMarkColor; }
                set { _waterMarkColor = value; Invalidate();/*thanks to Bernhard Elbl
                                                              for Invalidate()*/ }
            }

            private string _waterMarkText = "Water Mark";
            public string WaterMarkText
            {
                get { return _waterMarkText; }
                set { _waterMarkText = value; Invalidate(); }
            }
        #endregion

        //Default constructor
        public WaterMarkTextBox()
        {
            JoinEvents(true);
        }

        //Override OnCreateControl ... thanks to  "lpgray .. codeproject guy"
        protected override void OnCreateControl() 
        { 
            base.OnCreateControl();
            WaterMark_Toggel(null, null); 
        }

        //Override OnPaint
        protected override void OnPaint(PaintEventArgs args)
        {
            // Use the same font that was defined in base class
            System.Drawing.Font drawFont = new System.Drawing.Font(Font.FontFamily,
                Font.Size, Font.Style, Font.Unit);
            //Create new brush with gray color or 
            SolidBrush drawBrush = new SolidBrush(WaterMarkColor);//use Water mark color
            //Draw Text or WaterMark
            args.Graphics.DrawString((waterMarkTextEnabled ? WaterMarkText : Text),
                drawFont, drawBrush, new PointF(0.0F, 0.0F));
            base.OnPaint(args);
        }

        private void JoinEvents(Boolean join)
        {
            if (join)
            {
                this.TextChanged += new System.EventHandler(this.WaterMark_Toggel);
                this.LostFocus += new System.EventHandler(this.WaterMark_Toggel);
                this.FontChanged += new System.EventHandler(this.WaterMark_FontChanged);
                //No one of the above events will start immeddiatlly 
                //TextBox control still in constructing, so,
                //Font object (for example) couldn't be catched from within
                //WaterMark_Toggle
                //So, call WaterMark_Toggel through OnCreateControl after TextBox
                //is totally created
                //No doupt, it will be only one time call

                //Old solution uses Timer.Tick event to check Create property
            }
        }

        private void WaterMark_Toggel(object sender, EventArgs args )
        {
            if (this.Text.Length <= 0)
                EnableWaterMark();
            else
                DisbaleWaterMark();
        }

        private void EnableWaterMark()
        {
            //Save current font until returning the UserPaint style to false (NOTE:
            //It is a try and error advice)
            oldFont = new System.Drawing.Font(Font.FontFamily, Font.Size, Font.Style,
               Font.Unit);
            //Enable OnPaint event handler
            this.SetStyle(ControlStyles.UserPaint, true);
            this.waterMarkTextEnabled = true;
            //Triger OnPaint immediatly
            Refresh();
        }

        private void DisbaleWaterMark()
        {
            //Disbale OnPaint event handler
            this.waterMarkTextEnabled = false;
            this.SetStyle(ControlStyles.UserPaint, false);
            //Return back oldFont if existed
            if(oldFont != null)
                this.Font = new System.Drawing.Font(oldFont.FontFamily, oldFont.Size,
                    oldFont.Style, oldFont.Unit);
        }

        private void WaterMark_FontChanged(object sender, EventArgs args)
        {
            if (waterMarkTextEnabled)
            {
                oldFont = new System.Drawing.Font(Font.FontFamily,Font.Size,Font.Style,
                    Font.Unit);
                Refresh();
            }
        }
    }
}
24
Marcos Placona

私のために働いたもの:

this.waterMarkActive = true;
this.textBox.ForeColor = Color.Gray;
this.textBox.Text = "Type here";

this.textBox.GotFocus += (source, e) =>
  {
    if (this.waterMarkActive)
    {
      this.waterMarkActive = false;
      this.textBox.Text = "";
      this.textBox.ForeColor = Color.Black;
    }
  };

this.textBox.LostFocus += (source, e) =>
  {
    if (!this.waterMarkActive && string.IsNullOrEmpty(this.textBox.Text))
    {
      this.waterMarkActive = true;
      this.textBox.Text = "Type here";
      this.textBox.ForeColor = Color.Gray;
    }
  };

どこbool waterMarkActiveはクラスメンバー変数であり、textBoxTextBoxです。ただし、これはおそらくカプセル化する必要があります。

最近、Windowsがテキストボックスでウォーターマークをサポートしていることを発見しました。キューバナーと呼ばれます( here を参照)。実装は非常に簡単です。

// Within your class or scoped in a more appropriate location:
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, [MarshalAs(UnmanagedType.LPWStr)] string lParam);

// In your constructor or somewhere more suitable:
SendMessage(textBox.Handle, 0x1501, 1, "Please type here.");

textBoxTextBoxのインスタンス、0x1501はWindowsメッセージのコードですEM_SETCUEBANNERwParamTRUE(ゼロ以外)またはFALSE(ゼロ)のいずれかであり、lParamは希望するウォーターマークです表示する。 wParamは、キューバナーをいつ表示するかを示します。 TRUEに設定すると、コントロールにフォーカスがある場合でもキューバナーが表示されます。

40
Pooven

@Poovenの回答に基づいて(ありがとう!)、このクラスを作成しました。私のために働く。

/// <summary>
/// A textbox that supports a watermak hint.
/// </summary>
public class WatermarkTextBox : TextBox
{
    /// <summary>
    /// The text that will be presented as the watermak hint
    /// </summary>
    private string _watermarkText = "Type here";
    /// <summary>
    /// Gets or Sets the text that will be presented as the watermak hint
    /// </summary>
    public string WatermarkText
    {
        get { return _watermarkText; }
        set { _watermarkText = value; }
    }

    /// <summary>
    /// Whether watermark effect is enabled or not
    /// </summary>
    private bool _watermarkActive = true;
    /// <summary>
    /// Gets or Sets whether watermark effect is enabled or not
    /// </summary>
    public bool WatermarkActive
    {
        get { return _watermarkActive; }
        set { _watermarkActive = value; }
    }

    /// <summary>
    /// Create a new TextBox that supports watermak hint
    /// </summary>
    public WatermarkTextBox()
    {
        this._watermarkActive = true;
        this.Text = _watermarkText;
        this.ForeColor = Color.Gray;

        GotFocus += (source, e) =>
        {
            RemoveWatermak();
        };

        LostFocus += (source, e) =>
        {
            ApplyWatermark();
        };

    }

    /// <summary>
    /// Remove watermark from the textbox
    /// </summary>
    public void RemoveWatermak()
    {
        if (this._watermarkActive)
        {
            this._watermarkActive = false;
            this.Text = "";
            this.ForeColor = Color.Black;
        }
    }

    /// <summary>
    /// Applywatermak immediately
    /// </summary>
    public void ApplyWatermark()
    {
        if (!this._watermarkActive && string.IsNullOrEmpty(this.Text)
            || ForeColor == Color.Gray ) 
        {
            this._watermarkActive = true;
            this.Text = _watermarkText;
            this.ForeColor = Color.Gray;
        }
    }

    /// <summary>
    /// Apply watermak to the textbox. 
    /// </summary>
    /// <param name="newText">Text to apply</param>
    public void ApplyWatermark(string newText)
    {
        WatermarkText = newText;
        ApplyWatermark();
    }

}
8
Joel
  [DllImport("user32.dll", CharSet = CharSet.Auto)]
  private static extern Int32 SendMessage(IntPtr hWnd, int msg, int wParam, [MarshalAs(UnmanagedType.LPWStr)]string lParam);
  const int EM_SETCUEBANNER = 0x1501; 

  public Form1()
  {
      InitializeComponent();
      SendMessage(textBox1.Handle, EM_SETCUEBANNER, 1, "Username");
      SendMessage(textBox2.Handle, EM_SETCUEBANNER, 1, "Password");
  }

私は今学期にC#を学び始めたばかりなので、私は専門家ではありませんが、これは私のために働きました:(これはWindowsフォームを使用しています)

private void Form1_Load(object sender, EventArgs e)
{
    textBox1.SelectionStart = 0;  //This keeps the text
    textBox1.SelectionLength = 0; //from being highlighted
    textBox1.ForeColor = Color.Gray;
}

private void textBox_MouseMove(object sender, MouseEventArgs e)
{
    Cursor.Current = Cursors.IBeam; //Without this the mouse pointer shows busy
}

private void textBox1_KeyDown(object sender, KeyEventArgs e)
{
    if (textBox1.Text.Equals("Type here...") == true)
    {
        textBox1.Text = "";
        textBox1.ForeColor = Color.Black;
    }
}

private void textBox1_KeyUp(object sender, KeyEventArgs e)
{
    if (textBox1.Text.Equals(null) == true || textBox1.Text.Equals("") == true)
    {
        textBox1.Text = "Type here...";
        textBox1.ForeColor = Color.Gray;
    }
}
3
Michael Raatz

失われたフォーカスイベントを処理し、プロパティTextが空の場合、デフォルトの文字列を入力します。

1

Ahmed Soliman Flashaの回答に基づいて、次のクラスを使用します。

public class TextBoxHint : TextBox
{
    string _hint;

    [Localizable(true)]
    public string Hint
    {
        get { return _hint; }
        set { _hint = value; OnHintChanged(); }
    }

    protected virtual void OnHintChanged()
    {
        SendMessage(this.Handle, EM_SETCUEBANNER, 1, _hint);
    }     

    const int EM_SETCUEBANNER = 0x1501;

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern Int32 SendMessage(IntPtr hWnd, int msg, int wParam, [MarshalAs(UnmanagedType.LPWStr)]string lParam);
}
1
Tomas Kubes

これが(winformsとは対照的に)ASP.NETの場合、これを行うことができます。

JQueryを使用している場合、これをドキュメントに追加します(または、ページを初期化します)。

var $textbox = $("textbox selector"); // assumes you select a single text box
if ($textbox.val() == "") {
   $textbox.val("Type here to...");
   $textbox.one('focus', function() {
     $(this).attr('value', '');
   });
}

複数のテキストボックスを選択する場合は、いくつかの小さなリファクタリングを行う必要があります(要素のそれぞれの内部にifステートメントを配置します)。

1
macca1

C#の最後のバージョンでは、TextBoxにはPlaceholderTextプロパティがあり、すべて機能します。したがって、このプロパティの値として「Type here ...」を設定するだけです。

1
LuisDeveloper

@Joelの回答に基づきます。私は彼のクラスを修正しました(ベースに感謝します!)

/// <summary>
/// A textbox that supports a watermak hint.
/// Based on: https://stackoverflow.com/a/15232752
/// </summary>
public class WatermarkTextBox : TextBox
{
    /// <summary>
    /// The text that will be presented as the watermak hint
    /// </summary>
    private string _watermarkText;

    /// <summary>
    /// Gets or Sets the text that will be presented as the watermak hint
    /// </summary>
    public string WatermarkText
    {
        get { return _watermarkText; }
        set { _watermarkText = value; }
    }

    /// <summary>
    /// Whether watermark effect is enabled or not
    /// </summary>
    private bool _watermarkActive;
    /// <summary>
    /// Gets or Sets whether watermark effect is enabled or not
    /// </summary>
    public bool WatermarkActive
    {
        get { return _watermarkActive; }
        set { _watermarkActive = value; }
    }

    /// <summary>
    /// Create a new TextBox that supports watermak hint
    /// </summary>
    public WatermarkTextBox()
    {
        this.WatermarkActive = _watermarkActive;
        this.Text = _watermarkText;
    }

    protected override void OnCreateControl()
    {
        base.OnCreateControl();
        if (this.WatermarkActive)
            CheckWatermark();
    }

    protected override void OnGotFocus(EventArgs e)
    {
        base.OnGotFocus(e);
        CheckWatermark();
    }

    protected override void OnLostFocus(EventArgs e)
    {
        base.OnLostFocus(e);
        CheckWatermark();
    }        

    public void CheckWatermark()
    {
        if ((this.WatermarkActive) && String.IsNullOrWhiteSpace(this.Text))
        {
            ForeColor = Color.Gray;
            this.Text = _watermarkText;
        }
        else if ((this.WatermarkActive) && (!String.IsNullOrWhiteSpace(this.Text)))
        {
            if (this.Text == _watermarkText)
                this.Text = "";
            ForeColor = Color.Black;
        }
        else
            ForeColor = Color.Black;
    }
}
0
K1988

空になるまで、テキストボックスの背景に「ここに入力」という文字列を描画できます

0
Nagg

ユーザーがTextBoxにテキストを入力するまで「ここに入力...」を表示することは、最近ではよく知られているユーザビリティ機能です。この機能をC#でどのように実装しますか?

  1. 「ここに入力して...」としてtextbox.textを設定します

  2. box_click()などのイベントを作成します

  3. ->このコードをメソッドに追加します

    private void box_Click(object sender, EventArgs e)
    {
        Textbox b = (Textbox)sender;
        b.Text = null;
    }
    
  4. このメソッドをテキストボックスの「Enter」イベントに割り当てます(1つまたは複数)

0

これがASP.NET用の場合、 TextBoxWatermark を試すことができます。

これがWindows Formsの場合、これはすでに here SOで回答されています。

0
Ashish Gupta

HTMLウォーターマークへの同様の出力を生成

テキストボックスの「透かし」または「プレビュー」テキストのコードを次に示します。 Windowsフォームアプリケーションの使用。

[〜#〜] note [〜#〜]:この例には3つのテキストボックスがあり、それぞれに「mouse leave」イベントと「mouse enter」イベント用の以下のメソッドがあります。

private void textBoxFav_Leave(object sender, EventArgs e) {
  TextBox textbox = (TextBox)sender;
  if (String.IsNullOrWhiteSpace(textbox.Text)) {
    textbox.ForeColor = Color.Gray;
    if (textbox.Name == "textBoxFavFood") {
      textbox.Text = "Favorite Food";
    }
    else if (textbox.Name == "textBoxFavDrink") {
      textbox.Text = "Favorite Drink";
    }
    else if (textbox.Name == "textBoxFavDesert") {
      textbox.Text = "Favorite Desert";
    }
  }
  else {
    textbox.ForeColor = Color.Black;
  }
}

private void textBoxFav_Enter(object sender, EventArgs e) {
  TextBox textbox = (TextBox)sender;
  if (textbox.Text == "Favorite Food" || textbox.Text == "Favorite Drink" || textbox.Text == "Favorite Desert") {
    textbox.Text = "";
    textbox.ForeColor = Color.Black;
  }
}
0
Cordell

OnTextChangedを使用する理由TextBoxがフォーカスを取得したら、「Type here」というテキストを削除することをお勧めします。コントロールがフォーカスを失い、テキストが入力されていない場合、テキストを再度表示できます。

同じ結果で、トリッキーなロジックは不要です。

0
lboshuizen

コントロールのサイズ変更の問題やデータバインディングの問題を回避し、コードをよりシンプルにしたい場合は(わかりました、疑わしいです)、ラベルを使用して表示を切り替えることができます。それから

    private void FilterComboBox_GotFocus(object sender, EventArgs e)
    {
        FilterWatermarkLabel.Visible = false;
    }

    private void FilterComboBox_LostFocus(object sender, EventArgs e)
    {
        if (!FilterWatermarkLabel.Visible && string.IsNullOrEmpty(FilterComboBox.Text))
        {
            FilterWatermarkLabel.Visible = true;
        }
    }

画像の別のアプローチおよびデータバインディングの問題の回避もここにあります https://msdn.Microsoft.com/en-us/library/bb613590(v = vs.100).aspx

0
Empus