7

首先,我想说下面的示例过于简单化。假设您已绑定 WPF 控件。

<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>

Window 绑定到 Person 类,该类实现INotifyPropertyChanged并在表单中具有 Name setter

    public string Name 
    {
        get { return _name; }
        set 
        {
            _name = "Some Name";
            OnPropertyChanged("Name");
        }
    }

即,每当用户尝试从 UI 更改它时,_name 都会被分配“某个名称”。但是这个示例不起作用。我将 TextBox 中的名称更改为某个值,按选项卡强制焦点移动到 Button,尽管触发了 PropertyChanged 事件,但 TextBox 中的值保持不变。

你能解释一下为什么会这样吗?据我了解PropertyChanged,事件会强制 UI 从属性中重新读取值并显示它们,但在我的示例中,数据绑定文本框中的值未更新。


再次。我知道这是该属性的不良实现,但我想重复一遍,这是过于简单化了。这只是一个样本。但无论如何,PropertyChanged 表示属性已更改并且应该更新但它没有。

4

7 回答 7

9

TextBox 忽略 PropertyChanged 事件,因为它是事件的发起者。

一些澄清:

TextBox(或文本框上的绑定)知道它是发起者,因为它在同一个调用中接收到 PropertyChanged 事件。通过执行异步调用,文本框(或绑定)无法知道它是发起者,因此它将处理事件,就好像其他人更新了它一样

如果您将第二个文本框添加到您的 UI,您会看到第二个文本框在您编辑第一个文本框时确实发生了变化,反之亦然。

于 2009-01-26T19:40:23.030 回答
4

当绑定的UpdateSourceTriggerPropertyChanged时,Heinzi 建议的虚拟转换器解决方法(在此处描述)不起作用。但是,如果这是我们需要的呢?

似乎使绑定异步可以解决问题,例如:

SelectedIndex="{Binding SelectedIndex, IsAsync=True}"
于 2010-10-29T09:39:16.610 回答
2

正如 Bubblewrap 已经指出的那样,这是设计使然——文本框假定如果将绑定属性设置为某个值,则设置器不会更改该值。根据微软的说法,他们不会改变这种行为,因为这会破坏现有的代码。

如果您更改该值(是的,这样做有充分的理由),您必须使用一种解决方法,例如,通过添加一个虚拟转换器。有一篇博文(不是我写的)详细描述了这种技术。

于 2009-09-01T14:03:15.363 回答
0

原因是您在 setter 中硬编码了“Some Name”。当您更改 textBox 值时,实际上调用了 setter 并再次将“Some Name”设置为 propertyValue,因此它似乎没有在 UI 中更改。Put_name = value一切都会如你所愿,

于 2009-01-26T18:09:18.860 回答
0

如果我没记错的话,TextBox 上 Text 属性的默认绑定行为是 TwoWay,所以这应该可以工作。您可以像这样在 XAML 中强制它为 TwoWay:

<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=TwoWayBinding 声明中的 。

如果这不起作用,那么我怀疑在触发事件或分配属性的代码中引发了异常,您应该寻找它。


您似乎有可能正在调用以更改不是 UI 线程的线程上的值。如果是这种情况,那么您要么必须编组调用以在 UI 线程上触发属性更改事件,要么对 UI 线程上的值进行更改。

当对象绑定到 UI 元素时,必须在 UI 线程上对可能影响 UI 的对象进行更改。

于 2009-01-26T18:09:41.823 回答
0
public string MyField  
{  
    get { return _myField; }  
    set {   
        if (_myField == value)  
            return;  

        _myField = value;   

        OnPropertyChanged("MyField");  
    }  
}  

这是该属性的正确实现。

更改属性时,请确保对象的完全相同的实例绑定到控件。否则,将通知更改,但控件永远不会得到它,因为控件未正确绑定。

于 2009-01-26T18:14:27.633 回答
0

替换表单中的设置器

        set 
        {
            _name = "Some Name";
            Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.DataBind, 
                (SendOrPostCallback)delegate { OnPropertyChanged("Name"); },
                null);
        }

解决了这个问题,但它仍然是开放的。为什么我应该进行异步调用而不是同步发出我的属性已更改的信号。

于 2009-01-26T18:15:20.800 回答