Подтвердить что ты не робот

Как реализовать TextBox, который отображает "Тип здесь"?

Отображение "Type here to..." до тех пор, пока пользователь не вводит текст в TextBox, теперь является известной функцией юзабилити. Как реализовать эту функцию в С#?

Моя идея - переопределить OnTextChanged, но логика для обработки изменений текста и от "Тип здесь" немного сложна...

Отображение "Тип здесь" при инициализации и удаление его на первом входе легко, но я хочу отображать сообщение каждый раз, когда введенный текст становится пустым.

4b9b3361

Ответ 1

То, что вы ищете, - это текстовое поле с водяным знаком.

Там пример реализации С# здесь, все кредиты 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();
            }
        }
    }
}

Ответ 2

Что-то, что сработало для меня:

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 - переменная-член класса, а textBox - textBox. Это, вероятно, должно быть инкапсулировано, хотя:) Возможно, некоторые проблемы с этим подходом, но я в настоящее время не знаю о них.

Недавно я обнаружил, что Windows поддерживает водяные знаки в текстовых полях; они называются cue-баннерами (см. здесь). Это очень легко реализовать:

// 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.");

Где textBox - это экземпляр textBox, 0x1501 - это код для сообщения Windows EM_SETCUEBANNER, wParam может быть либо TRUE (отличным от нуля), либо FALSE (ноль), а lParam - знак воды, который вы хотите отобразить. wParam указывает, когда должен отображаться баннер метки; если установлено значение TRUE, тогда значок метки будет отображаться даже тогда, когда элемент управления имеет фокус.

Ответ 3

Основываясь на ответе @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();
    }

}

Ответ 4

  [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");
  }

Ответ 5

Я только начинаю изучать С# в этом семестре, поэтому я не эксперт, но это сработало для меня: (Это использует формы 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;
    }
}

Ответ 6

Обработать событие потерянного фокуса и, если свойство Text пусто, заполните его по умолчанию.

Ответ 7

Если это ASP.NET(в отличие от winforms), вы можете сделать это:

Если вы используете 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 внутри каждого элемента).

Ответ 8

В последней версии С# у TextBox есть свойство PlaceholderText, которое все работает. Поэтому вам нужно только установить "Тип здесь..." в качестве значения этого свойства.

Ответ 9

На основе ответа Ахмеда Солимана 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);
}

Ответ 10

Вы можете нарисовать строку "Тип здесь" на фоне текстового поля до тех пор, пока она не станет пустой.

Ответ 11

Если это для ASP.NET, вы можете попробовать TextBoxWatermark.

Если это для Windows Forms, на это уже ответил здесь в SO.

Ответ 12

Зачем использовать OnTextChanged? Я бы предложил удалить текст "Тип здесь", когда TextBox получает фокус. Когда элемент управления теряет фокус и текст не вводится, вы можете снова отобразить текст.

Тот же результат и не требует сложной логики.

Ответ 13

ПРОИЗВОДИТ ПОДОБНЫЙ ВЫХОД В HTML WATERMARK

Вот мой код для текстового поля "водяной знак" или "превью" текста - отлично работает! Использование приложения Windows Forms.

ПРИМЕЧАНИЕ. В этом примере есть 3 текстовых поля, каждый из которых имеет метод ниже для события "выключение мыши" и событие "мыши".

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;
  }
}

Ответ 14

Если вы хотите избежать проблем с изменением размера и проблем с привязкой данных и сделать код более простым (хорошо, это сомнительно), вы можете просто использовать ярлык и переключить его видимость. Тогда

    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

Ответ 15

На основе ответа @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;
    }
}

Ответ 16

  Отображение "Введите здесь...", пока пользователь не введет текст в TextBox, в настоящее время является широко известной функцией юзабилити. Как реализовать эту функцию в С#?

  1. Установите для textbox.text значение "Введите здесь..."

  2. создать событие, скажем, box_click()

  3. -> Поместите этот код в свой метод

    private void box_Click(object sender, EventArgs e)
    {
        Textbox b = (Textbox)sender;
        b.Text = null;
    }
    
  4. Теперь назначьте этот метод событию "Enter" вашего текстового поля (возможно, одного или нескольких)