WPF 数据绑定和 IValueConverter
为什么当我在 WPF 中的绑定表达式中使用转换器时,数据更新时值没有更新。
我有一个简单的 Person 数据模型:
class Person : INotifyPropertyChanged
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
我的绑定表达式如下所示:
<TextBlock Text="{Binding Converter={StaticResource personNameConverter}" />
我的转换器如下所示:
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();
}
}
如果我在没有转换器的情况下绑定数据,效果很好:
<TextBlock Text="{Binding Path=FirstName}" />
<TextBlock Text="{Binding Path=LastName}" />
我缺少什么?
编辑: 只是为了澄清一些事情,Joel 和 Alan 对于需要实现的 INotifyPropertyChanged 接口都是正确的。 实际上我确实实现了它,但它仍然不起作用。
我无法使用多个 TextBlock 元素,因为我试图将窗口标题绑定到全名,并且窗口标题不采用模板。
最后,可以选择添加复合属性“FullName”并绑定到它,但我仍然想知道为什么当绑定使用转换器时不会发生更新。 即使我在转换器代码中放置一个断点,当对底层数据进行更新时,调试器也无法到达那里:-(
谢谢, 乌里
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您还可以使用 MultiBinding.. 绑定到 Person 对象、FirstName 和 LastName。 这样,一旦 FirstName 或 LastName 抛出属性更改事件,该值就会更新。
或者,如果您只使用 FirstName 和 LastName,则将 Person 对象从绑定中剥离为如下所示:
MultiValueConverter 如下所示:
但是当然,所选答案也可以工作,但 MultiBinding 工作得更优雅......
You can also use a MultiBinding.. Bind to the Person object, the FirstName and LastName. That way, the value gets updated as soon as FirstName or LastName throws the property changed event.
Or if you only use the FirstName and LastName, strip the Person object from the binding to something like this:
And the MultiValueConverter looks like this:
But of course, the selected answer works as well, but a MultiBinding works more elegantly...
(请参阅下面的编辑;最新:#2)
它不会更新,因为您的
Person
对象无法通知任何FirstName
或LastName
已更改。 查看此问题。以下是实现 INotifyPropertyChanged 的方法。 (已更新,请参阅编辑 2)
编辑 1
实际上,因为您需要更新名字和姓氏,并且
Path=FirstName
和这样工作得很好,我认为你根本不需要转换器。 多个TextBlock
同样有效,并且在本地化为从右到左的语言时实际上可以更好地工作。编辑2
我已经弄清楚了。 它不会被通知属性已更新,因为它绑定到对象本身,而不是这些属性之一。 即使当我将
Person
设置为DependencyObject
并设置FirstName
和LastName
DependencyProperties
时,它不会更新。您将必须使用
FullName
属性,我已经更新了上面的Person
类的代码来反映这一点。 然后就可以绑定Title
了。 :我已将Person
对象设置为Window
的DataContext
。)(注意 编辑
TextBox
中的名称并希望名称更改立即反映出来,而不是在TextBox
失去焦点时,您可以这样做:我知道您不想使用
FullName
属性,但是任何能够实现您想要的功能的东西都可能有点像 Rube Goldberg 设备。 例如在Window
类本身上实现INotifyPropertyChanged
和Person
属性,让Window
监听>PropertyChanged
事件以触发Window
的PropertyChanged
事件,并使用如下所示的相对绑定。 您还可以在InitializeComponent()
之前设置Person
属性,或者在设置Person
属性之后触发PropertyChanged
,以便当然,它会出现。 (否则在InitializeComponent()
期间它将为null
,并且需要知道它何时是Person
。)(see edits below; latest: #2)
It isn't updating because your
Person
object is not capable of notifying anything that the value ofFirstName
orLastName
has changed. See this Question.And here's how you implement
INotifyPropertyChanged
. (Updated, see Edit 2)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. MultipleTextBlocks
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
aDependencyObject
and madeFirstName
andLastName
DependencyProperties
, it wouldn't update.You will have to use a
FullName
property, and I've update the code of thePerson
class above to reflect that. Then you can bind theTitle
. (Note: I've set thePerson
object as theWindow
'sDataContext
.)If you're editing the names in a
TextBox
and want the name changed reflected immediately instead of when theTextBox
loses focus, you can do this: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 implementingINotifyPropertyChanged
and aPerson
property on theWindow
class itself, having theWindow
listen on thePropertyChanged
event in order to fire theWindow
'sPropertyChanged
event, and using a relative binding like the following. You'd also have set thePerson
property beforeInitializeComponent()
or firePropertyChanged
after setting thePerson
property so that it shows up, of course. (Otherwise it will benull
duringInitializeComponent()
and needs to know when it's aPerson
.)为了更新绑定,您的 person 类需要实现 INotifyPropertyChanged 以使绑定知道对象的属性已被更新。 您还可以通过提供 fullName 属性来避免额外的转换器。
您的绑定现在如下所示:
In Order for the binding to be updated, your person class needs to implement INotifyPropertyChanged to let the binding know that the object's properties have been udpated. You can also save yourself from the extra converter by providing a fullName property.
Your Binding will now look like this:
我还没有检查过,但你也可以尝试以下方法吗
I haven't check it but can you also try the following