Dependency Properties are super great and they eliminate a lot of unnecessary code. In this post I will explain a problem with Custom Dependency Properties when using DataBinding operations. The example is taken from WPF Unleashed by Adam Nathan.
The basic purpose of the FileInputBox control is to display the selected File Path in the TextBox. You can achieve the same result by simply adding the TextBox assignment code in the Button click event (browse button). But dependency properties will allow you to be more flexible as you can easily achieve this using the XAML code.
Here is the complete code for the FileInputBox user control:
<UserControl x:Class="WPF3D.FileInputBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300" x:Name="root">
<Grid>
<StackPanel>
<TextBox Name="txtFileName" Text="{Binding FileName, ElementName=root}" Width="300" Height="20"></TextBox>
<Button Name="BtnSelectFile" Content="Browse..." Width="100" Height="20" Click="BtnSelectFile_Click"></Button>
</StackPanel>
</Grid>
</UserControl>
The Text property uses the FileName dependency property. Let's check out the User Control code. Here is the FileName Dependency Property.
public static readonly DependencyProperty FileNameProperty = DependencyProperty.Register("FileName",
typeof (String),
typeof (FileInputBox));
The FileName is a simple string property that will return the dependency property.
public string FileName
{
get { return (string) GetValue(FileNameProperty); }
set { SetValue(FileNameProperty, value); }
}
And the button click code which will open the file dialog is as follows:
private void BtnSelectFile_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog fileDialog = new OpenFileDialog();
fileDialog.ShowDialog();
this.FileName = fileDialog.FileName;
}
This is the same code that is used in WPF Unleashed. The above code will *NOT* work. You will be able to select a file from your machine but it will not display in the TextBox. There seems to be a problem with WPF when using binding with custom dependency properties. The solution is to create a callback method which will be fired when the dependency property changes. The solution was posted by Tim Hibbard. You can read the solution here.
And here is the dependency property modified to use the callback. Once, this code is in place everything will work as expected.
public static readonly DependencyProperty FileNameProperty = DependencyProperty.Register("FileName",
typeof (String),
typeof (FileInputBox),new UIPropertyMetadata(
String.Empty,
textChangedCallback));
private static void textChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
FileInputBox input = (FileInputBox) d;
input.txtFileName.Text = e.NewValue as String;
}
Hope it helps!