プレースホルダーとかウォーターマークなどと呼ばれる機能(入力例やヒントなどが透かしのように表示される機能)を追加した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プロパティを変更する。



コメント
コメントを投稿