WPF Data Binding and IValueConverter
c#, converters, data-binding, wpf
Solution
(see edits below; latest: #2)
It isn't updating because your `Person` object is not capable of notifying anything that the value of `FirstName` or `LastName` has changed. See this Question.
And here's how you implement `INotifyPropertyChanged`. (Updated, see Edit 2)
using System.ComponentModel;
class Person : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
string _firstname;
public string FirstName {
get {
return _firstname;
}
set {
_firstname = value;
onPropertyChanged( "FirstName", "FullName" );
}
}
string _lastname;
public string LastName {
get {
return _lastname;
}
set {
_lastname = value;
onPropertyChanged( "LastName", "FullName" );
}
}
public string FullName {
get {
return _firstname + " " + _lastname;
}
}
void onPropertyChanged( params string[] propertyNames ) {
PropertyChangedEventHandler handler = PropertyChanged;
if ( handler != null ) {
foreach ( var pn in propertyNames ) {
handler( this, new PropertyChangedEventArgs( pn ) );
}
}
}
}
Edit 1
Actually, since you're after the first name and last name updating, and `Path=FirstName` and such works just fine, I don't think you'll need the converter at all. Multiple `TextBlocks` are just as valid, and can actually work better when you're localizing to a right-to-left language.
Edit 2
I've figured it out. It's not being notified that the properties have updated because it is binding to the object itself, not one of those properties. Even when I made `Person` a `DependencyObject` and made `FirstName` and `LastName` `DependencyProperties`, it wouldn't update.
You will have to use a `FullName` property, and I've update the code of the `Person` class above to reflect that. Then you can bind the `Title`. (Note: I've set the `Person` object as the `Window`'s `DataContext`.)
Title="{Binding Path=FullName, Mode=OneWay}"
If you're editing the names in a `TextBox` and want the name changed reflected immediately instead of when the `TextBox` loses focus, you can do this:
<TextBox Name="FirstNameEdit"
Text="{Binding Path=FirstName, UpdateSourceTrigger=PropertyChanged}" />
I know you didn't want to use a `FullName` property, but anything that would accomplish what you want would probably be a bit of a Rube Goldberg device. Such as implementing `INotifyPropertyChanged` and a `Person` property on the `Window` class itself, having the `Window` listen on the `PropertyChanged` event in order to fire the `Window`'s `PropertyChanged` event, and using a relative binding like the following. You'd also have set the `Person` property before `InitializeComponent()` or fire `PropertyChanged` after setting the `Person` property so that it shows up, of course. (Otherwise it will be `null` during `InitializeComponent()` and needs to know when it's a `Person`.)
<Window.Resources>
<loc:PersonNameConverter
x:Key="conv" />
</Window.Resources>
<Window.Title>
<Binding
RelativeSource="{RelativeSource Self}"
Converter="{StaticResource conv}"
Path="Person"
Mode="OneWay" />
</Window.Title>
Problem
Why is it that when I use a converter in my binding expression in WPF, the value is not updated when the data is updated. I have a simple Person data model: ``` class Person : INotifyPropertyChanged { public string FirstName { get; set; } public string LastName { get; set; } } ``` My binding expression looks like this: ``` <TextBlock Text="{Binding Converter={StaticResource personNameConverter}" /> ``` My converter looks like this: ``` class PersonNameConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { Person p = value as Person; return p.FirstName + " " + p.LastName; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } ``` If I bind the data without a converter it works great: ``` <TextBlock Text="{Binding Path=FirstName}" /> <TextBlock Text="{Binding Path=LastName}" /> ``` What am I missing? EDIT: Just to clarify a few things, both Joel and Alan are correct regarding the INotifyPropertyChanged interface that needs to be implemented. In reality I do actually implement it but it still doesn't work. I can't use multiple TextBlock elements because I'm trying to bind the Window Title to the full name, and the Window Title does not take a template. Finally, it is an option to add a compound property "FullName" and bind to it, but I'm still wondering why updating does not happen when the binding uses a converter. Even when I put a break point in the converter code, the debugger just doesn't get there when an update is done to the underlying data :-( Thanks, Uri