2011-02-04 14 views
41

カーソルが入ったときに消えるウォーターマークのテキストを最初に表示する基本的なWindowsフォームTextBoxの優れた実装方法を教えてもらえますか?私はEnterとLeaveのイベントをいくつか創造的に使って自分自身を作り出すことができると思っていますが、どこかで完璧に使える実装があると確信しています。私はWPFの実装を見て、必要に応じてネストすることができましたが、ネイティブのWinForms TextBoxの派生が良いでしょう。WinFormsのウォーターマークのTextBox

これまでのところこれがあります。まだそれを試していないが、誰も眩しい問題を参照してくださいですか?

public class WatermarkTextBox:TextBox 
{ 
    public string WatermarkText { get; set; } 

    public Color WatermarkColor { get; set; } 

    private Color TextColor { get; set; } 

    private bool isInTransition; 

    public WatermarkTextBox() 
    { 
     WatermarkColor = SystemColors.GrayText; 
    } 

    private bool HasText { get { return Text.IsNotNullOrBlankOr(WatermarkText); }} 

    protected override void OnEnter(EventArgs e) 
    { 
     base.OnEnter(e); 

     if (HasText) return; 

     isInTransition = true; 
     ForeColor = TextColor; 
     Text = String.Empty; 
     isInTransition = false; 
    } 

    protected override void OnForeColorChanged(EventArgs e) 
    { 
     base.OnForeColorChanged(e); 
     if (!isInTransition) //the change came from outside 
      TextColor = ForeColor; 
    } 

    protected override void OnLeave(EventArgs e) 
    { 
     base.OnLeave(e); 

     if (HasText) return; 

     isInTransition = true; 
     ForeColor = WatermarkColor; 
     Text = WatermarkText.EmptyIfNull(); 
     isInTransition = false; 
    } 
} 

EDIT:上記のコードは最終的にはいくつかの精巧さで動作しましたが、CueProviderはもっとうまく機能しました。最終的な実装は次のとおりです。

public class WatermarkTextBox:TextBox 
{ 
    private string watermarkText; 
    public string WatermarkText 
    { 
     get { return watermarkText; } 
     set 
     { 
      watermarkText = value; 
      if (watermarkText.IsNullOrBlank()) 
       CueProvider.ClearCue(this); 
      else 
       CueProvider.SetCue(this, watermarkText); 
     } 
    } 
} 

私はCueProvider機能を完全に統合できましたが、これは美しく機能します。

+6

透かしが一意(紙の外側に電子透かしと呼ばれる)は、その用紙をタグ紙に画像またはパターンです。キューバナーは、あなたが何を記述しているかという言葉です。 – Tergiver

+0

Jay Riggsの削除済み回答:[CueProvider](http://www.codeproject.com/kb/edit/cueprovider.aspx)を試してください –

答えて

76

公式の用語は「キューバナー」です。これを行うもう1つの方法があります.TextBoxを継承するだけで、ジョブも完了します。プロジェクトに新しいクラスを追加し、以下に示すコードを貼り付けます。コンパイル。新しいコントロールをツールボックスの上部からドロップし、Cueプロパティを設定します。

フォームのLanguageプロパティにローカライズされたデザイナでCue値のライブプレビューが表示されます。 Winformsの優れた部分の優れたデモンストレーション、非常に小さなバックのための多くの強打。

using System; 
using System.ComponentModel; 
using System.Windows.Forms; 
using System.Runtime.InteropServices; 

class CueTextBox : TextBox { 
    [Localizable(true)] 
    public string Cue { 
     get { return mCue; } 
     set { mCue = value; updateCue(); } 
    } 

    private void updateCue() { 
     if (this.IsHandleCreated && mCue != null) { 
      SendMessage(this.Handle, 0x1501, (IntPtr)1, mCue); 
     } 
    } 
    protected override void OnHandleCreated(EventArgs e) { 
     base.OnHandleCreated(e); 
     updateCue(); 
    } 
    private string mCue; 

    // PInvoke 
    [DllImport("user32.dll", CharSet = CharSet.Unicode)] 
    private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, string lp); 
} 
+2

ニース!魅力的な作品! – friederbluemle

+6

この方法の問題点は、ボックスにテキストがなくても、テキストボックスにフォーカスが当てばキューテキストが消えることです。既定のフォーカスを取得するテキストボックスを持つフォームがある場合、キューはユーザーに表示されず、キューの目的全体が無効になります。 –

+3

私が見つけた問題は、複数行のテキストボックスコントロールをサポートしていないことでした。私はMultilineをサポートするためにこのクラスをどのように変更できるかは不明です。 –

27

私は、定数を導入pinvoke.netの定義とそれの一貫性を保つため、コードはFxCopの検証に合格できるようにするために、上記の@Hansアンパッサンによって与えられた答えを更新しました。

class CueTextBox : TextBox 
{ 
    private static class NativeMethods 
    { 
     private const uint ECM_FIRST = 0x1500; 
     internal const uint EM_SETCUEBANNER = ECM_FIRST + 1; 

     [DllImport("user32.dll", CharSet = CharSet.Unicode)] 
     public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, string lParam); 
    } 

    private string _cue; 

    public string Cue 
    { 
     get 
     { 
      return _cue; 
     } 
     set 
     { 
      _cue = value; 
      UpdateCue(); 
     } 
    } 

    private void UpdateCue() 
    { 
     if (IsHandleCreated && _cue != null) 
     { 
      NativeMethods.SendMessage(Handle, NativeMethods.EM_SETCUEBANNER, (IntPtr)1, _cue); 
     } 
    } 

    protected override void OnHandleCreated(EventArgs e) 
    { 
     base.OnHandleCreated(e); 
     UpdateCue(); 
    } 
} 

編集:更新のPInvokeが安全側に誤るために、CharSet属性を設定するために呼び出します。詳細はSendMessageページpinvoke.netをご覧ください。

+0

FxCopのファンではなく、私の背中を覆っていただきありがとうございます(私のスタイルを痙攣させる)。しかし、私は、あなたがCharSetを使用せずにSendMessageのUnicode Wバージョンを宣言したことに気づいただけです。これは確実に機能しますか? –

+0

@HansPassant私は[pinvoke.net](http://www.pinvoke.net/default.aspx/user32/SendMessage.html)から定義を得たと思います。それは 'MarshalAs'か' CharSet'属性のどちらかが使われなければならないと述べています。私は両方をテストして、少なくともXP64では正常に動作します(!)。しかし、私は 'CharSet'を使った方がはっきりしているように思っています。 私は、FxCop/StyleCop/R#を仕事に使用しなければならない人のために「FxCop版」を作成し、赤い下線を避けたい:)。 –

12
[DllImport("user32.dll", CharSet = CharSet.Unicode)] 
private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, string lParam); 

とメッセージ定数:

private const uint EM_SETCUEBANNER = 0x1501; 
private const uint CB_SETCUEBANNER = 0x1703; // minimum supported client Windows Vista, minimum supported server Windows Server 2008 

そして、それを実現するための最良の方法は、拡張メソッドとしてある私見。
だからTextBoxコントロールのための構文は次のようになります。コードから

MyTextBox.CueBanner(false, "Password"); 

public static void CueBanner(this TextBox textbox, bool showcuewhenfocus, string cuetext) 
{ 
    uint BOOL = 0; 
    if (showcuewhenfocus == true) { BOOL = 1; } 

    SendMessage(textbox.Handle, EM_SETCUEBANNER, (IntPtr)BOOL, cuetext); ; 
} 
+1

このようにpinvoke宣言をすることはできません。 32ビットコード(int32を返す)でも64ビットコード(wparamはint64)でも正しくありません。それは偶然に作用する傾向がありますが、あなたが幸運を止めると、それがなぜ機能しなくなったのかを考え出すチャンスはありません。 –

+0

oops、typo fixed、ありがとうございます。 – deegee

+3

+1拡張メソッドのために、私が思っていたものが最も良いと思っていた – tallseth

0
Private Sub randomSubName() Handles txtWatermark.Click 
    txtWatermark.text = "" 
End Sub 

あなたは透かしがなりたいものは何でもテキストボックスのデフォルトのテキストを作り、私が想定しこの例では、テキストボックスにtxtWatermarkという名前を付けます。

ねえ、私は新しいです。私はひどくポストをめちゃくちゃにあれば...私も分からない、これが動作するかどうか...ここで

+3

ようこそStackOverflow。 [質問への回答](https://stackoverflow.com/help/how-to-answer)をご覧ください。特に、誰かのためにコードを投稿する場合は、何かが機能することを確認してください。 – Celeo

7

がヒント(または透かしやキュー)を示すサポートTextBoxの実装ですので、申し訳ありません:

  • MultiLineが真の場合のヒントも表示されます。
  • これはメッセージWM_PAINTの処理とヒントの描画に基づいています。ヒントをカスタマイズし、ヒントカラーのようなプロパティを追加することも、ヒントを表示するタイミングを右から左に描画することも、コントロールすることもできます。
using System.Drawing; 
using System.Windows.Forms; 
public class ExTextBox : TextBox 
{ 
    string hint; 
    public string Hint 
    { 
     get { return hint; } 
     set { hint = value; this.Invalidate(); } 
    } 
    protected override void WndProc(ref Message m) 
    { 
     base.WndProc(ref m); 
     if (m.Msg == 0xf) 
     { 
      if (!this.Focused && string.IsNullOrEmpty(this.Text) 
       && !string.IsNullOrEmpty(this.Hint)) 
      { 
       using (var g = this.CreateGraphics()) 
       { 
        TextRenderer.DrawText(g, this.Hint, this.Font, 
         this.ClientRectangle, SystemColors.GrayText , this.BackColor, 
         TextFormatFlags.Top | TextFormatFlags.Left); 
       } 
      } 
     } 
    } 
} 

次のリポジトリから作業例をダウンロードすることができます:あなたはEM_SETCUEBANNERを使用する場合は、2つの問題があるだろう

。テキストは常にシステムのデフォルトカラーで表示されます。また、TextBoxMultiLineの場合、テキストは表示されません。

ペイントソリューションを使用すると、任意の色でテキストを表示できます。コントロールが複数行であるときにも、ウォーターマークを表示することができ:

enter image description here

+0

これをTextBoxコントロールの拡張機能として使用できますか? – 707

+1

@Yawz 'TextBox'から継承しています。このクラスをプロジェクトに追加した後、プロジェクトをビルドすると 'ExTextBox'コントロールがツールボックスに追加され、フォームにドロップできます。 –

関連する問題