Wpf INotifyPropertyChanged问题
首先我想说,下面的示例过于简单化了。 假设您已经绑定了WPF控件Wpf INotifyPropertyChanged问题,wpf,data-binding,inotifypropertychanged,Wpf,Data Binding,Inotifypropertychanged,首先我想说,下面的示例过于简单化了。 假设您已经绑定了WPF控件 <Window Title="Window1" Height="300" Width="300"> <Grid> <StackPanel> <TextBox Text="{Binding Name}" Margin="10"/> <Button HorizontalAlignment="Center" Content="
<Window Title="Window1" Height="300" Width="300">
<Grid>
<StackPanel>
<TextBox Text="{Binding Name}" Margin="10"/>
<Button HorizontalAlignment="Center"
Content="Click Me" Margin="5"
Padding="2" Click="OnButtonClick" />
</StackPanel>
</Grid>
</Window>
也就是说,每当用户试图从UI更改某个名称时,都会为该名称分配“某个名称”。
但这个示例不起作用。我将TextBox中的名称更改为某个值,按tab键强制焦点移动到按钮,TextBox中的值保持不变,尽管触发了PropertyChanged事件
你能解释一下为什么会这样吗?据我所知,PropertyChanged
事件强制用户界面从属性中重新读取值并显示它们,但在我的示例中,数据绑定文本框中的值不会更新
再说一遍。我理解这是对属性的糟糕实现,但我想重申,这是过于简单化了。 这只是一个样本。
但无论如何,PropertyChanged表示属性已更改,应该更新,但它没有更改。原因是您在setter中硬编码了“某个名称”。当您更改文本框值时,setter实际上会被调用,它会再次将“Some Name”设置为propertyValue,以便在UI中看起来不会被更改。
放置
\u name=value
,事情就会像您预期的那样工作,如果我没有弄错的话,TextBox上文本属性的默认绑定行为是双向的,因此应该可以工作。您可以在XAML中强制它是双向的,如下所示:
<Window Title="Window1" Height="300" Width="300">
<Grid>
<StackPanel>
<TextBox Text="{Binding Name, Mode=TwoWay}" Margin="10"/>
<Button HorizontalAlignment="Center"
Content="Click Me" Margin="5"
Padding="2" Click="OnButtonClick" />
</StackPanel>
</Grid>
</Window>
注意绑定声明中的Mode=TwoWay
如果这不起作用,那么我怀疑触发事件或分配属性的代码中正在抛出异常,您应该查找它
似乎有一种可能性,您正在调用以更改非UI线程的线程上的值。如果是这种情况,则必须封送调用以在UI线程上触发property changed事件,或者对UI线程上的值进行更改
public string MyField
{
get { return _myField; }
set {
if (_myField == value)
return;
_myField = value;
OnPropertyChanged("MyField");
}
}
当对象绑定到UI元素时,必须在UI线程上对可能影响UI的对象进行更改
public string MyField
{
get { return _myField; }
set {
if (_myField == value)
return;
_myField = value;
OnPropertyChanged("MyField");
}
}
这是该属性的正确实现
更改属性时,请确保将完全相同的对象实例绑定到控件。否则,将通知更改,但控件将永远无法获得更改,因为控件未正确绑定。替换表单中的setter
public string Name
{
get { return _name; }
set
{
_name = "Some Name";
OnPropertyChanged("Name");
}
}
set
{
_name = "Some Name";
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.DataBind,
(SendOrPostCallback)delegate { OnPropertyChanged("Name"); },
null);
}
解决了该问题,但仍处于打开状态。为什么我应该进行异步调用,而不是同步发送我的属性已更改的信号。文本框会忽略PropertyChanged事件,因为它是事件的发起方 一些澄清: TextBox(或TextBox上的绑定)知道它是启动器,因为它在同一调用中接收PropertyChanged事件。通过执行异步调用,文本框(或绑定)无法知道它是发起方,因此它将处理事件,就像其他人更新了它一样
如果将第二个文本框添加到UI中,您将看到第二个文本框在编辑第一个文本框时会发生更改,反之亦然。正如Bubblewrap已经指出的那样,这是经过设计的——文本框假设如果将绑定属性设置为某个值,则setter不会更改该值,他们不会更改此行为,因为这会破坏现有代码
如果要更改该值(是的,有充分的理由这样做),则必须使用变通方法,例如,通过添加虚拟转换器。有(不是我写的)详细描述了这项技术。当绑定的UpdateSourceTrigger被属性更改时,Heinzi(描述的)建议的虚拟转换器解决方案不起作用。但如果这是我们需要的呢 使绑定异步似乎可以达到目的,例如:
SelectedIndex="{Binding SelectedIndex, IsAsync=True}"
TextBox(或TextBox上的绑定)知道它是启动器,因为它在同一调用中接收PropertyChanged事件。通过执行异步调用,文本框(或绑定)无法知道它是发起方,因此它将处理事件,就像其他人更新了itErr一样。我可能错了,但它不应该是
{binding Path=Name}
?不。对于属性绑定,您可以省去路径作为快捷方式。这是因为绑定有一个以路径为参数的构造函数。我认为OP实际上希望每次有人更改属性值时,无论键入什么,属性值都是“某个名称”。