
Под катом, будем пошаговое руководство, по разработке такого компонента, ориентированное на тех, кто первый раз подходит к разработке своих элементов управления. Для тех, кто уже программирует под Windows Store откровений не будет, но если не сложно, выложите рекомендации в комментариях, может кто-то действительно решит сделать хороший элемент управления для такой задачки.
Поехали.
Создаем новое Windows Store приложение. В Solution добавляем новую сборку (правый клик мыши на Solution, в контекстном меню Add -> New Project):

В эту сборку добавляем новый элемент (правый клик на проекте, Add -> New Item):

В файле cs нашего контрола, меняем предка на TextBox:
public sealed partial class WaterMarkedTextBox : TextBox
Также, нам придется поменять разметку, заменив базовый компонент и удалив содержимое:

Эти нехитрые действия, позволили нам получить в своем компоненте все поля и методы, которые были у базового TextBox-а. Единственно, что нас не устраивает, это отсутствие у TextBox-а возможности показывать подсказку. Переопределим шаблон нашего потомка TextBox-а, добавив в него TextBlock, для отображения подсказки:
<TextBox.Template>
<ControlTemplate TargetType="TextBox">
<Grid>
<TextBox Text="{Binding Text, RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}" />
<TextBlock
Text="{Binding WaterMark, RelativeSource={RelativeSource TemplatedParent}}"
Foreground="Gray" Margin="5,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Center" Visibility="Collapsed" IsHitTestVisible="False"/>
</Grid>
</ControlTemplate>
</TextBox.Template>
Т.к. в конструкторе работать с визуальными компонентами еще нельзя, то подпишемся на событие загрузки компонента и всю полезную работу будем выполнять в обработчике этого события:
public WaterMarkedTextBox()
{
this.InitializeComponent();
Loaded += WaterMarkedTextBox_Loaded;
}
Для определения, есть у нас фокус на элементе или нет, добавим поле:
private bool _isFocused;
Ну и нам понадобиться DependencyProperty, для хранения текста подсказки:
/// <summary>
/// Подсказка показываемая пользователю
/// </summary>
public string WaterMark
{
get { return (string)GetValue(WaterMarkProperty); }
set { SetValue(WaterMarkProperty, value); }
}
/// <summary>
/// Static part of dependency property WaterMark
/// </summary>
public static readonly DependencyProperty WaterMarkProperty =
DependencyProperty.Register("WaterMark", typeof(string), typeof(WaterMarkedTextBox), new PropertyMetadata(""));
Все, пишем обработку загрузки компонента, получения фокуса ввода и потери его:
void WaterMarkedTextBox_Loaded(object sender, RoutedEventArgs e)
{
var grid = (Grid)VisualTreeHelper.GetChild(this, 0);
TextBox innerTextBox = (TextBox)grid.Children[0];
innerTextBox.GotFocus += WaterMarkedTextBox_GotFocus;
innerTextBox.LostFocus += WaterMarkedTextBox_LostFocus;
ChangeWatermarkTextVisibility();
}
void WaterMarkedTextBox_LostFocus(object sender, RoutedEventArgs e)
{
_isFocused = false;
ChangeWatermarkTextVisibility();
}
void WaterMarkedTextBox_GotFocus(object sender, RoutedEventArgs e)
{
_isFocused = true;
ChangeWatermarkTextVisibility();
}
Ну и самый последний метод, для изменения видимости подсказки:
private void ChangeWatermarkTextVisibility()
{
var grid = (Grid)VisualTreeHelper.GetChild(this, 0);
TextBlock watermarkText = (TextBlock)grid.Children[1];
if (!string.IsNullOrEmpty(Text) || _isFocused)
{
watermarkText.Visibility = Visibility.Collapsed;
}
else
{
watermarkText.Visibility = Visibility.Visible;
}
}
Собираем решение.
Т.к. я в качестве исходного проекта взял Blank App, то на главную форму внес вот такую разметку:
<Page x:Class="App11.MainPage"
xmlns:MyControls="using:MyControls"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App11"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<StackPanel Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<TextBlock Text="Укажите сотрудника:" />
<MyControls:WaterMarkedTextBox WaterMark="Введите часть ФИО и нажмите Enter" />
</StackPanel>
</Page>
Чтобы не думать о подключении namespace, я обычно новые компоненты перетягиваю на форму из панели Tools:

Ну а как все это выглядит, можно посмотреть в первой картинке этого поста, ну или повторив мои действия и запустив приложение.