プレースホルダーとかウォーターマークなどと呼ばれる機能(入力例やヒントなどが透かしのように表示される機能)を追加したTextBoxを作成する。
TextBoxに何も入力されていない場合に透かしが表示され、何か入力されると透かしが消える。
入力すると
→
WPFにはAdornerというUIElementを装飾する為の抽象クラスがある。
Adornerを使ってTextBoxコントロールの上に透かし表示用のTextBlockを重ねて表示する仕組み。
Adornerを継承したクラスを作成
public class WatermarkedAdorner : Adorner { private TextBlock watermark; private VisualCollection visualChildren; public WatermarkedAdorner(UIElement adornedElement) : base(adornedElement) { watermark = new TextBlock(); watermark.Margin = new Thickness(5, 3, 5, 3); watermark.Opacity = 0.3; watermark.IsHitTestVisible = false; visualChildren = new VisualCollection(this); visualChildren.Add(watermark); } protected override Size ArrangeOverride(Size finalSize) { var element = this.AdornedElement as FrameworkElement; var x = 0; var y = 0; var w = element.ActualWidth; var h = element.ActualHeight; watermark.Arrange(new Rect(x, y, w, h)); return finalSize; } protected override int VisualChildrenCount { get { return visualChildren.Count; } } protected override Visual GetVisualChild(int index) { return visualChildren[index]; } public void SetWatermarkText(string text) { watermark.Text = text; } }
透かし表示用のTextBlockコントロールを作成 (9~12行目)
TextBlockコントロールを作成する。
透かしっぽく薄く表示させるためOpacityプロパティを使って少し透過させて表示する。
このコントロールがクリックに反応しないようにIsHitTestVisibleプロパティをfalseに設定。
作成したコントロールの管理 (14~15行目)
作成したTextBlockコントロールはVisualCollectionクラスを使って管理する。
Adornerが子要素を管理する場合、VisualChildrenCountプロパティとGetVisualChildメソッドをオーバライドして適切な値を返すよう作り込む必要がある。
※既存のコントロールを使わずDrawingContextを使って独自の描画を行うだけの場合は、VisualCollectionで管理する必要は無く
OnRenderをオーバーライドして描画を実装する
VisualCollectionクラスを作成して、そこに作成したTextBlockコントロールを追加する。
サイズが変更されたらTextBlockコントロールのサイズも変える (18~28行目)
ArrangeOverrideメソッドをオーバーライドする。
TextBlockコントロールのArrangeメソッド呼び出してサイズを変える。
Adornerで既存コントロールを管理する為のお約束 (30~38行目)
VisualChildrenCountプロパティをオーバーライドしてVisualCorrectionの件数を返す。
GetVisualChildメソッドをオーバライドしてVisualCorrectionの指定番目の要素を返す。
透かしの文字列を変更するメソッドを作成 (40~43行目)
TextBlockのTextに値をセットするメソッドを用意する。
Adornerを追加したTextBoxを作成
public class WatermarkedTextBox : TextBox { public static readonly DependencyProperty WatermarkProperty = DependencyProperty.Register( "Watermark", // プロパティ名を指定 typeof(string), // プロパティの型を指定 typeof(WatermarkedTextBox), // プロパティを所有する型を指定 new UIPropertyMetadata("", (d, e) => {(d as WatermarkedTextBox).OnWatermarkPropertyChanged(e); })); public string Watermark { get { return (string)GetValue(WatermarkProperty); } set { SetValue(WatermarkProperty, value); } } private WatermarkedAdorner MyAdoner; protected override void OnInitialized(EventArgs e) { base.OnInitialized(e); this.Loaded += new RoutedEventHandler(InitializeAdorner); } private void InitializeAdorner(object sender, RoutedEventArgs e) { var layer = AdornerLayer.GetAdornerLayer(this); MyAdoner = new WatermarkedAdorner(this); MyAdoner.SetWatermarkText(Watermark); layer.Add(MyAdoner); } protected override void OnTextChanged(TextChangedEventArgs e) { if (null != MyAdoner) { if (string.IsNullOrEmpty(this.Text)) MyAdoner.Visibility = Visibility.Visible; else MyAdoner.Visibility = Visibility.Collapsed; } } protected void OnWatermarkPropertyChanged(DependencyPropertyChangedEventArgs e) { if (null != MyAdoner) { MyAdoner.SetWatermarkText(e.NewValue.ToString()); } }
透かし用文字列のプロパティを作成 (3~14行目)
透かし用の文字列をセットするWatermarkプロパティを依存関係プロパティとして作成。
依存関係プロパティについてはこちらを参照。
OnInitializedメソッドをオーバーライド (19~23行目)
ロード時にAdornerをセットする為に、Loadedイベントにハンドラーを追加。
ロード時にAdornerをセットする (25~31行目)
AdornerLayerクラスのGetAdornerLayerメソッドを使ってAdonerを追加するレイヤーを取得。
そのレイヤーに作ったAdornerを追加する。
透かし文字の表示・非表示を制御 (33~42行目)
OnTextChangedメソッドをオーバーライドして、TextBoxに入力値が有るか無いかによって、AdornerのVisivilityプロパティを変更する。
コメントをお書きください