I found a new control for the AvalonControlsLibrary, the MaskedTextBox. I found this control while reading one of the best WPF books around from Matthew MacDonald.
The MaskedTextBox is a normal WPF textbox (in fact it inherits from the TextBox class) that formats the text entered by the user (and also strings set from the Text property programmatically). For example if you type 1234567890 into a masked textbox that has a U.S. telephone number mask, the text will be displayed as (123) 456-7890. To check out how you can create Masks have a look at this url.
To create this control I use the MaskTextProvider which is a .Net class. The MaskedTextProvider takes care of validating the string and also to format the text entered accordingly to the mask specified.
The MaskedTextBox has a Mask property which accepts a string. This string (and the mask property) is then used to create a MaskedTextProvider that can format the user input.
In order to intercept the user input, I override the OnPreviewTextInput method and apply the mask to the text that has been entered. As you can see this is 80% of the control’s code.
/// override this method to replace the characters enetered with the mask
/// <param name=”e”>Arguments for event</param>
protected override void OnPreviewTextInput(TextCompositionEventArgs e)
int position = SelectionStart;
MaskedTextProvider provider = MaskProvider;
if (position < Text.Length)
position = GetNextCharacterPosition(position);
if (provider.Replace(e.Text, position))
if (provider.InsertAt(e.Text, position))
position = GetNextCharacterPosition(position);
e.Handled = true;
I also override the OnPreviewKeyDown method of the TextBox in order to handle special characters such as delete and backspace.Yet we have a problem! The problem is that if the user uses cut or paste the mask will not be applied until the next keystroke. So the workaround (described in the book) shows us how we can use CommandBinding to suppress these features. I really liked the idea because this shows us how commands can give us such power in our hands. So to suppress these features we have to do the following///<summary>
/// Default constructor
//cancel the paste and cut command
CommandBindings.Add(new CommandBinding(ApplicationCommands.Paste, null, CancelCommand));
CommandBindings.Add(new CommandBinding(ApplicationCommands.Cut, null, CancelCommand));
//cancel the command
private static void CancelCommand(object sender, CanExecuteRoutedEventArgs e)
e.CanExecute = false;
e.Handled = true;
} As you can see all you have to do is handle the command yourself and just set the CanExecute to false and Handled to true. Nice!Another problem is how we can force the Text property to apply the Mask when set programmatically. Since we only handle the OnPreviewTextInput this is not catered for. And here comes the FrameworkMetaData. Basically we can override the default meta data for the Text property and apply a CoerceValueCallback that apply the mask to the text./// <summary>
/// Static Constructor
//override the meta data for the Text Proeprty of the textbox
FrameworkPropertyMetadata metaData = new FrameworkPropertyMetadata();
metaData.CoerceValueCallback = ForceText;
}//force the text of the control to use the mask
private static object ForceText(DependencyObject sender, object value)
MaskedTextBox textBox = (MaskedTextBox) sender;
if (textBox.Mask != null)
MaskedTextProvider provider = new MaskedTextProvider(textBox.Mask);
} This shows us how powerful Dependency properties are. I was really excited about this one since it’s my first time to play around and override property meta data explicitly :)
And that’s basically it.Eventually I will implement a real MaskedTextBox by inheriting from the TextBoxBase but for now this will do the trick for developers that need this control.Hope you find this control useful.Downlaod control demo and full source code
I have created a WPF group, where WPF developers can talk, share knowledge and also solve WPF issues… Have a look and maybe also contribute at http://groups.google.com/group/wpf-disciples?hl=en
I created a page for the AvalonControlsLibrary. This page contains information related to the Control Library that I am building.
Feedback is much appreciated
[UPDATED - 16th October 2007]
What is development without unit testing?
For me it is just chaos! You make a bug fix and you end up giving birth to another 3… Also if you don’t have unit tests, refactoring becomes a risk!
When developing software using WPF you will hit a brick wall when creating your first unit test. You will encounter the InvalidOperationException curse.. The NUnit test runner will show you the red light and tell you: InvalidOperationException Failed to set the specified COM apartment state.
The cause of this problem is that NUnit runs in an MTA while WPF must run in STA. I found the solution to this problem here. I also added this class in my AvalonUnitTesting library. Basically to run unit tests that are WPF related you can use a class called AvalonTestRunner and call the RunInSta method passing a delegate. This will auto magically switch the current thread apartment to STA for you… an example of such a test is the following
/// Test running on an STA Thread
public void TestMainWindow()
MainWindow window = new MainWindow();
WPF is a very strong and powerful UI platform. I don’t know why I said that but I just felt like saying it Anyway back to unit testing. How can you unit test control and maybe even simulate user interaction? I found a very interesting solution here.Yet I still wanted more… So I kept searching …One thing that you will surely notice is that when using cool features of WPF such as DataBinding, you never get exceptions. The reason is that WPF has silent exceptions (If i might say sometimes silent but deadly :0 ). The exceptions in data binding are still happening but they are handled by the WPF framework and displayed in the output window of the Visual studio. For more information about the Tracing in WPF have a look here.
While reading this blog I got an idea. I said why don’t I create a trace listener that can assert when ever a WPF data binding exception is raised.. Basically this solution can make your XAML data binding testable! So I created a class that listens to these data binding warning and asserts to show the developer that there is a problem in his XAML. To use these feature all you have to do is 1 line of code as you will se in the example.
/// Unit Tests wpf data binding
public class WPFSampleApplicationTests
public void TestDataBindingForControls()
//test the main window XAML.
//This will assert all data binding errors
//runs the test for a specific user control
In this example I am testing a Window for data binding. I am also testing a user control in the second line of code of the TestDataBindingForControls method. So basically with this solution you can test both Window, pages and also custom controls (or user controls)… Please note that when you pass an object that is not of type Window the RunDataBindingTests methods takes care of wrapping your control in a window and run all data binding tests. If you have a control that uses data bindings that assumes that the control is always in a specific window (which would be a situation where your control needs some serios re thinking) this solution would not work. Since the wrapper window would not have the same objects loaded! Any way feel free to download the full source and start playing around… Please let me know if you need any help using the library…DOWNLOAD FULL SOURCE CODE
As promised this weekend I re-wrote the TreeListBox (previous article posted here) control to support better virtualization… Basically I changed the whole idea… There are the same properties and same interface so whoever was using the old TreeListBox can just make an update and everything should work properly.
What was wrong in the old implementation was that I was generating the TreeListBoxItems instead of letting the VirtualizingStackPanel to generate them; the VirtualizingStackPanel was only not adding them to the logical tree! I realized this when I was profiling the component for memory.
In the new implementation I changed the whole concept. Basically now I generate a list of TreeListBoxInfo object from the HierarchalItemsSource specified by the user and set it to the ItemsSource of the TreeListBox.
The object transformation is something like the following
List of Persons – > treelistbox.HierarchalItemsSource -> List of TreeListBoxInfo – > treelistBox.ItemsSource
Basically the TreeListBoxInfo is just an intermediate object that contains information such as the Level, Children and of course it stores the actual data item (in the example above the data item would be the person object)
Ok, so we have a flat list now but if I set the ItemsSource to have a list of TreeListBoxInfo this would mean that all DataTemplates for the TreeListBoxItem would not work because the user doesn’t know that the Items in the ItemsSource are of type TreeListBoxInfo! So here what we do is override the PrepareContainerForItemOverride method. This method allows us to change the object to set for the TreeListBoxItem and so we do the following…
/// Prepares the new VirtualizingTreeViewItem with the actual business object
/// <param name=”element”>The element (VirtualizingTreeViewItem) to apply the template</param>
/// <param name=”item”>The business object to set</param>
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
TreeListBoxItem listItem = element as TreeListBoxItem;
TreeListBoxInfo actualItem = item as TreeListBoxInfo;
//prepares the item with the relative VirtualizingTreeViewInfo
//pass the actual data item instead of the VirtualizingTreeViewInfo
As you can see we replace the item to prepare with the DataItem of the TreeListBoxInfo.
There is a lot of other things going on in the background such as registering to data binding events for children and finding the correct index where to push a new item in the list but I think that this is all you need to start working!
Please send me an email at firstname.lastname@example.org if you find any bugs or even if you have any suggestions.
Thanks for your support !
[Last Update of Source Code - 06 October 2007 - fixed some memory leaks]