Introduction
Databinding is one of the things that UI developers need constantly. WPF offers some nice things for databinding. Additionally, WPF offers alleviation to some operations that where not difficult, but uncomfortable to do in WinForms. Examples of these techniques were setting window transparency and shape. Now, it's ridiculously easy to make a window (or any UI element) rounded. I'll also throw in a context menu stuff. I think this is useful information for beginner WPF programmers. Hopefully, you enjoy this article!
To summarize, we're going to go through the following areas:
- Databinding
- Moving the cursor inside a textbox
- Rounded windows
- Transparency
- Context menu
Let's see how they operate...
Using the code
Here are the use cases for the attached example code:
- Printing out the databound name
- Changing the name
- Seeing the state ("originality") of the databound object
- Resetting the name to its original value
- Setting the transparency of the window
- Moving the window
- Closing the app
Databinding
In our example, the name
property is a member property in an underlying business class called Person
. The user can see and change the name
property from the UI's textbox. The user can see the internal state of the underlying Person
from a text block where a textual hint is given. The hint basically just tells the user if the entered name is the original one or not - enough to prove that the underlying data object really changes. All changes are propagated between the UI and the underlying data object on-the-fly without any programmatic functions, and this is called as "Two-way databinding" in WPF.
The Person
class is the source for databinding:
class Person : INotifyPropertyChanged
{
string name;
public string OriginalName = "Timo";
public string Name
{
get { return name; }
set
{
name = value;
Notify("Name");
}
}
public Person()
{
this.Name = OriginalName;
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
void Notify(string propName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
#endregion
}
As mentioned earlier, "Two-way databinding" ensures that changes from the UI to propagate to the Person
object. Another way around, the -side probably wants to know when changes happen in the Person
object. This is done by implementing the INotifyPropertyChanged
interface in the Person
class. This interface might be familiar from old WinForms programs and its function is to add an event to the implementing class. Later on, the consuming class (in this case, the Window object) needs to subscribe to the PropertyChanged
event, like this:
PersonObject = new Person();
PersonObject.PropertyChanged += new
System.ComponentModel.PropertyChangedEventHandler(PersonObject_PropertyChanged);
this.DataContext = PersonObject;
PersonObject.Name = PersonObject.OriginalName;
In the above code snippet, it's noteworthy to mention about setting the Window
object's DataContext
to the Person
object.
The target for databinding is a textbox:
<TextBox Text="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Width="120"
Height="Auto"
Margin="5"
Name="textBox1"
Background="Yellow"
FontWeight="Bold"
VerticalAlignment="Center"
HorizontalAlignment="Stretch"
Loaded="textBox1_MoveCursorToEnd"
GotFocus="textBox1_MoveCursorToEnd"/>
Now, when the content of the Person
object's Name
-property changes, the label text also changes. And, because the binding mode is set to "TwoWay
", the changes in UI will propagate to the Person
object. Nice and tidy, isn't it?
When looking at the code, you'll find a strange call to the ResetToOriginalName()
method from the Window
object's Initialized()
method. In the ResetToOriginalName()
method, the Name
property is set and the focus is set to the textbox. Now, it's important to notice that WPF databinding does not need to be ordered to update the target, it's done automatically. I'm updating the source (Person
object's Name
property) in order to pass some time so that the WPF system has enough time to set up the UI.
Moving the cursor
Moving the cursor at the end of the text box's current content is done in the textBox1_MoveCursorToEnd()
method, which is bound to the textbox's GotFocus
event. Check it from the code. It's a small piece of code but does wonders to the user experience.
Rounded window
In WPF, rounded windows are easy to do. First, the window-object's WindowStyle
property is set to None
and the Background
property is set to Transparent
. Secondly, a Border
control is used to give the window it's rounded rectangular shape. The Border
control has a CornerRadius
property, which I've set to 20,20,20,20 in the example code.
Transparency
Window transparency is simpler to achieve in WPF than in WinForms. It's just a matter of setting the window-object's Opacity
property to a value between 0.0 (totally transparent) and 1.0 (totally opaque).
Context menu
Context menus are fun and intuitive to use. The window class has a ContextMenu
attached property, which I've used in the example code like this:
<Window.ContextMenu>
<ContextMenu Background="LightGreen">
<MenuItem Header="Transparent" Click="TransparencyMenuItem_Click" IsCheckable="True"/>
<MenuItem Header="Close" Click="CloseMenuItem_Click" IsCheckable="False"/>
</ContextMenu>
</Window.ContextMenu>
The above code adds two menu items (Transparent
and Close
) and binds them with the Click
event handlers. It's noteworthy to point out that a menu item can be checkable or non-checkable, and there's a property for setting that.
Points of Interest
The process of databinding business objects to UI has become significantly more elegant with WPF. There are some tricks of the trade to be learned, namely the order in which the binding happens in relation to the UI rendering. This must be kept in mind when specific user experience is to be grasped. The best way to learn WPF is to roll up your sleeves and hit your hands into the dirt. This avoids having to hit your head to the monitor when deadlines are closing in.
I hope you liked this beginner level article. Feedback is welcome!
History
- Version 1.0 - submitted on 5.5.2008.