WPF、ツールチップ付きの入力フィールド

テキストが欠落している瞬間にヒントを表示する入力フィールドの効果を作成すると便利な場合があります。
たとえば、次のように:
ツールチップ付きの入力フィールドの例

これは、スペースを節約したり、特別なフィールドを強調表示したり、まったく理解していないユーザーにヒントを与えたりする必要がある場合に役立ちます。

何が必要ですか?
まず、ツールチップのテキストを担当するプロパティ。 それなしでは、何かを表示することは非常に困難です。
空のクラスを作成します。
public class WatermarkedTextBox : DependencyObject
{
#region Fields

private const string _defaultWatermark = "None" ;

public static readonly DependencyProperty WatermarkTextProperty = DependencyProperty.Register( "WatermarkText" , typeof ( string ), typeof (WatermarkedTextBox), new UIPropertyMetadata( string .Empty, OnWatermarkTextChanged));

#endregion

#region Constructor(s)

/// <summary>
/// Initializes a new instance of the <see cref="WatermarkedTextBox"/> class with default watermark text.
/// </summary>
public WatermarkedTextBox()
: this (_defaultWatermark)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="WatermarkedTextBox"/> class.
/// </summary>
/// <param name="watermark">The watermark to show when value is <c>null</c> or empty.</param>
public WatermarkedTextBox( string watermark)
{
WatermarkText = watermark;
}

#endregion

#region Properties

public string WatermarkText
{
get { return ( string )GetValue(WatermarkTextProperty); }
set { SetValue(WatermarkTextProperty, value ); }
}

#endregion

#region Methods

public static void OnWatermarkTextChanged(DependencyObject box, DependencyPropertyChangedEventArgs e)
{
//Add changed functionality here
}

#endregion
}


* This source code was highlighted with Source Code Highlighter .
空白が作成され、ヒントを使用して操作するために必要なプロパティとメソッドが用意できたので、実装に直接進むことができます。 多くの実装オプションを考え出すことができます:
たとえば、テキストのインストールレシートにハンドラーを掛けて、ツールチップをプレーンテキストとして表示できます(これはさまざまなhtml形式でよく見られます)。
TextBoxを集約し、ロジックを記述して、独自のデータを表示できます。
ただし、WPFのコンテキストでは、3番目に最も正しい方法を使用します。 スタイルを使用してコントロールの表示を再定義します。つまり、コントロールテンプレートを再定義します。

すぐに言ってやった。 開始するには、( DependencyObject代わりに) TextBoxからクラスを継承しTextBox
ここを見ると、次のテキストが表示されます。
TextBoxのControlTemplateには、コンテンツホスト要素としてタグ付けされた要素が1つだけ含まれている必要があります。 この要素は、TextBoxのコンテンツをレンダリングするために使用されます。 要素をコンテンツホストとしてタグ付けするには、特別な名前PART_ContentHostを割り当てます。 コンテンツホスト要素は、ScrollViewerまたはAdornerDecoratorでなければなりません。 コンテンツホスト要素は、子要素をホストできません。
これは、テンプレートでPART_ContentHostという名前のScrollViewerを作成する必要があることを意味します。
したがって、陰湿な計画は次のとおりですTextBox内にTextBoxが存在しない時点で、別のTextBlockから準備されたテキストを表示しTextBox 。そうでない場合は、通常のTextBoxふりをしTextBox

つまり、スタイル内のどこかは次のようになります。
< TextBlock x:Name ="WatermarkText" Text ="{TemplateBinding WatermarkText}" Foreground ="Gray" Margin ="5,0,0,0" HorizontalAlignment ="Left" VerticalAlignment ="Center" Visibility ="Collapsed" IsHitTestVisible ="False" />

* This source code was highlighted with Source Code Highlighter .
インデントと色の形でいくつかの美しさを追加したので、努力がより顕著になります。

そして、それのために次のトリガーを書くことが可能になります:
< MultiTrigger.Conditions >
< Condition Property ="IsKeyboardFocusWithin" Value ="False" />
< Condition Property ="Text" Value ="" />
</ MultiTrigger.Conditions >
< Setter Property ="Visibility" TargetName ="WatermarkText" Value ="Visible" />
</ MultiTrigger >
< MultiTrigger >
< MultiTrigger.Conditions >
< Condition Property ="IsKeyboardFocusWithin" Value ="False" />
< Condition Property ="Text" Value ="{x:Null}" />
</ MultiTrigger.Conditions >
< Setter Property ="Visibility" TargetName ="WatermarkText" Value ="Visible" />
</ MultiTrigger >


* This source code was highlighted with Source Code Highlighter .
テキストフィールドに値がなく、フィールドが入力状態とは異なる状態になったときに、ヒントテキストが提供されます。 残念ながら、 文字列 .Emptyとnullが同様に適切に処理されるように、2つのほぼ同一のトリガーを作成する必要があります
したがって、uのすべてのコンポーネントが利用可能になり、それらを結合することは残ります。 これは複雑なことではありません。
< Style TargetType ="{x:Type WatermarkedTextBox:WatermarkedTextBox}" BasedOn ="{StaticResource {x:Type TextBox}}" >
< Setter Property ="Template" >
< Setter.Value >
< ControlTemplate TargetType ="{x:Type WatermarkedTextBox:WatermarkedTextBox}" >
< Grid >
< ScrollViewer x:Name ="PART_ContentHost" />
< TextBlock x:Name ="WatermarkText" Text ="{TemplateBinding WatermarkText}" Foreground ="Gray" Margin ="5,0,0,0" HorizontalAlignment ="Left" VerticalAlignment ="Center" Visibility ="Collapsed" IsHitTestVisible ="False" />
</ Grid >
< ControlTemplate.Triggers >
< MultiTrigger >
< MultiTrigger.Conditions >
< Condition Property ="IsKeyboardFocusWithin" Value ="False" />
< Condition Property ="Text" Value ="" />
</ MultiTrigger.Conditions >
< Setter Property ="Visibility" TargetName ="WatermarkText" Value ="Visible" />
</ MultiTrigger >
< MultiTrigger >
< MultiTrigger.Conditions >
< Condition Property ="IsKeyboardFocusWithin" Value ="False" />
< Condition Property ="Text" Value ="{x:Null}" />
</ MultiTrigger.Conditions >
< Setter Property ="Visibility" TargetName ="WatermarkText" Value ="Visible" />
</ MultiTrigger >
</ ControlTemplate.Triggers >
</ ControlTemplate >
</ Setter.Value >
</ Setter >
</ Style >


* This source code was highlighted with Source Code Highlighter .
ページスタイルに追加されたすべてのパーツをきれいに接続しました。 理論的には、歓声を上げてエクスタシーに足を踏み入れることができますが、アプリケーションを実行すると、フレームがどこかで消えたことがわかります。 グリッドをラップすることにより、この不正を回復しようとします。
< Style TargetType ="{x:Type WatermarkedTextBox:WatermarkedTextBox}" BasedOn ="{StaticResource {x:Type TextBox}}" >
< Setter Property ="Template" >
< Setter.Value >
< ControlTemplate TargetType ="{x:Type WatermarkedTextBox:WatermarkedTextBox}" >
< Border Background ="{TemplateBinding Background}" BorderBrush ="{TemplateBinding BorderBrush}" BorderThickness ="{TemplateBinding BorderThickness}" >
< Grid >
< ScrollViewer x:Name ="PART_ContentHost" />
< TextBlock x:Name ="WatermarkText" Text ="{TemplateBinding WatermarkText}" Foreground ="Gray" Margin ="5,0,0,0" HorizontalAlignment ="Left" VerticalAlignment ="Center" Visibility ="Collapsed" IsHitTestVisible ="False" />
</ Grid >
</ Border >
< ControlTemplate.Triggers >
< MultiTrigger >
< MultiTrigger.Conditions >
< Condition Property ="IsKeyboardFocusWithin" Value ="False" />
< Condition Property ="Text" Value ="" />
</ MultiTrigger.Conditions >
< Setter Property ="Visibility" TargetName ="WatermarkText" Value ="Visible" />
</ MultiTrigger >
< MultiTrigger >
< MultiTrigger.Conditions >
< Condition Property ="IsKeyboardFocusWithin" Value ="False" />
< Condition Property ="Text" Value ="{x:Null}" />
</ MultiTrigger.Conditions >
< Setter Property ="Visibility" TargetName ="WatermarkText" Value ="Visible" />
</ MultiTrigger >
</ ControlTemplate.Triggers >
</ ControlTemplate >
</ Setter.Value >
</ Setter >
</ Style >

* This source code was highlighted with Source Code Highlighter .
これで作業は完了です。 結果を楽しむことができます。 または、実際の例をダウンロードします

Source: https://habr.com/ru/post/J71151/


All Articles