I’m having yet another WPF binding issue. Just when I think I’ve got this stuff figured out, I run into more problems… :S
Anyway… I’ve created a custom user control for selecting files. It’s a simple textbox followed by a button contained within a grid. The property of the control with which I am working is called FilePath and the TextBox on this control is bound to that property. When the button is clicked, a SaveFileDialog is opened and the user selects a file. The UI correctly updates after the user selects the file.
The problem I seem to be having is that when I bind an object to the control (in this instance I have an object with a DocumentFilePath property) the object doesn’t update when a new file is selected.
Here’s the relevant code within my user control:
public static readonly DependencyProperty FilePathProperty = DependencyProperty.Register("FilePath", typeof(string), typeof(FileSave), new UIPropertyMetadata(string.Empty, OnFilePathChanged));
public string FilePath
{
get
{
return this.GetValue(FilePathProperty) as string;
}
set
{
this.SetValue(FilePathProperty, value);
this.OnPropertyChanged("FilePath");
}
}
private void OnPropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
private static void OnFilePathChanged(object sender, DependencyPropertyChangedEventArgs e)
{
((FileSave)sender).OnPropertyChanged("FilePath");
}
And the user control is added into my Window programatically by using reflection on my object:
private void AddFileSave(PropertyInfo pi)
{
FileSave fs = new FileSave();
Binding b = new Binding(pi.Name);
fs.SetBinding(FileSave.FilePathProperty, b);
this.AddToGrid(fs); //adds the control into my window's grid in the correct row and column; nothing fancy here
}
It may be worth noting that if I load the window with an existing object, my user control displays properly but still won’t register any changes within the object to which it is bound.
Please let me know if you guys need any more info.
Thanks in advance,
Sonny
EDIT: I’ve found a way around the problem, but this probably isn’t a good solution. By watching the debugger carefully I found that when I set the FilePath property within my control, the object was being unbound. If anyone can shed some light on that, I would be most appreciative. In the mean time, I’ve changed the code that opens my SaveFileDialog to look like this:
private void Button_Click(object sender, RoutedEventArgs e)
{
Microsoft.Win32.OpenFileDialog ofd = new Microsoft.Win32.OpenFileDialog();
ofd.Multiselect = false;
ofd.Title = "Select document to import...";
ofd.ValidateNames = true;
ofd.ShowDialog();
if (this.GetBindingExpression(FilePathProperty) == null)
{
this.FilePath = ofd.FileName;
}
else //set value on bound object (THIS IS THE NEW PORTION I JUST ADDED)
{
BindingExpression be = this.GetBindingExpression(FilePathProperty);
string propName = be.ParentBinding.Path.Path;
object entity = be.DataItem;
System.Reflection.PropertyInfo pi = entity.GetType().GetProperty(propName);
pi.SetValue(entity, ofd.FileName, null);
}
if (!string.IsNullOrWhiteSpace(this.FilePath))
{
_fileContents = new MemoryStream();
using (StreamReader sr = new StreamReader(this.FilePath))
{
_fileContents = new MemoryStream(System.Text.ASCIIEncoding.ASCII.GetBytes(sr.ReadToEnd()));
}
}
else
{
_fileContents = null;
}
}
You’re not specifying anywhere in your code that the FilePath property should be TwoWay so updates of the DP value won’t get pushed to the bound source object’s property. You can use either:
or you can set up your Dependency Property to use a default of TwoWay:
You should also follow Robert’s suggestion of removing the manual PropertyChange event, and also don’t EVER add any code other than GetValue and SetValue in your DP wrapper property. XAML calls GetValue and SetValue directly so will skip over anything else you add there – which can lead to very nasty bugs.