Unless you have been living under a rock the past few days you already know about the recent release of Windows 8 Consumer Preview and Visual Studio 11 Beta. Since I know you already downloaded and installed all the shiny new toys, let’s take a quick look at how to get started writing a custom control for the new metro style applications. There is no better control to start with than the ever popular WatermarkTextBox control.
Setting up the Solution
First start off by creating a new metro style application in Visual Studio 11 beta. A blank application will work just fine for our purposes.
When your solution loads right click the project and select" “Add New Item”. When the dialog appears choose the “Template Control” item template. Of course give it a name of WatermarkTextBox.
You will notice that the Template control is just like a Silverlight or WPF custom control. It comes with a class file and a corresponding style in the Generic.xaml file.
Writing the Control
Our WatermarkTextBox control is going to derive from the TextBox class that is already provided by Microsoft.
Having said that, we don’t want to reinvent the wheel when it comes to styling the TextBox we are deriving from. So let’s save some time by dropping a TextBox onto the BlankPage.xaml page. Now right click the TextBox on the design surface and select “Edit Template –> Edit a Copy”. This will create the default TextBlock style that we can use in our WatermarkTextBox ControlTemplate.
Now open up the Generic.xaml file and replace this:
Let’s test what we have so far. Add an instance of our WatermarkTextBox control to the BlankPage.xaml.
Looks great. Just like the default Windows TextBox. Now we need to start adding our Watermark elements to it. Obviously we need a property for our Watermark. Your first thought maybe to define it as a type of string, but I want to support any element, not just text, so I will define it as a type of Object. This will allow me to nest controls inside of the Watermark property instead of being restricted to a simple string.
I also want to define a DataTemplate that will be used to define the ContentTemplate for the Watermark.
Now we need to modify our control template to support our new Watermark property. We will do this by simply adding a ContentPresenter to our Template.
Oh, and don’t forget the ContentTemplate that will define the default look for our watermark. This is placed at the top of the Generic.xaml.
And we need to set the default value in a style setter.
As you can see, I placed the ComtentPresenter after the ContentElement and before the DeleteButton elements. You may have also noticed that I set the visibility to Collapsed. This is because by default I want the Watermark hidden. So that means we need to add some code to show the watermark when the text box has no focus and it has no text. First we need to add some visual states to the VisualStateManager.
Next we need to add some code to handle the GotFocus and LostFocus events of the TextBox. Start by adding event handlers for the events in the constructor.
Now add the code that does the heavy lifting.
One last thing is to make sure we set the visual state when the template is applied. So override the OnApplyTemplate method as follows.
That should do it. Now let check it out in action. Be sure to provide a watermark for our control.
Yes, we found a bug
Everything seems to be working perfectly. Until you actually try to use a watermark that isn’t text. Try using this as your watermark.
Now let’s see our results.
Hey! Where is my watermark? Well there appears to be a bug with a ContentPresenter/ContentControl that will not display content when the ContentTemplate has been set and the Content is anything else except a string. This just so happens to be the exact same bug that exists in Silverlight. Interesting I know. So how do we fix it? We have to delete the usage of our Watermarktemplate until this gets fixed.
Now let’s see what happens.
Now that’s much better. Let’s hope this is just a beta bug.