2010-06-16 78 views
6

我有一个文本框,其值是绑定到一个ViewModel属性:WPF文本框的值不会改变OnPropertyChanged

 <TextBox Name="txtRunAfter" Grid.Column="4" Text="{Binding Mode=TwoWay, Path=RunAfter}" Style="{StaticResource TestStepTextBox}"/> 

设定,直到我尝试添加一些验证,如果值是得到了工作正常设置为:

private int _runAfter = 0; 
    public string RunAfter 
    { 
     get 
     { 
      return _runAfter.ToString(); 
     } 

     set 
     { 
      int val = int.Parse(value); 

      if (_runAfter != val) 
      { 
       if (val < _order) 
        _runAfter = val; 
       else 
       { 
        _runAfter = 0; 
        OnPropertyChanged("RunAfter"); 
       } 
      } 
     } 
    } 

虽然OnPropertyChanged已达到(我已经说过),但视图并未更改。 我该如何做这项工作?

感谢, 何塞·塔瓦雷斯

回答

5

问题是,您正在更新Binding的源,而Binding正在更新您的属性。 WPF在引发PropertyChanged事件时不会检查您的属性值,以响应Binding更新。

set 
{ 
    int val = int.Parse(value); 

    if (_runAfter != val) 
    { 
     if (val < _order) 
     { 
      _runAfter = val; 
      OnPropertyChanged("RunAfter"); 
     } 
     else 
     { 
      _runAfter = 0; 
      Dispatcher.CurrentDispatcher.BeginInvoke(
       new Action<String>(OnPropertyChanged), 
       DispatcherPriority.DataBind, "RunAfter"); 
     } 
    } 
} 

更新:

我注意到的另一件事是,在你的TextBoxBinding使用默认设置您可以通过使用Dispatcher延迟事件的传播中的一个分支,解决这个问题UpdateSourceTrigger,当TextBox失去焦点时发生。在此模式下TextBox失去焦点后,您将不会看到文字更改回0。如果将其更改为PropertyChanged,则会立即看到此情况。否则,你的财产将不会被置直到你TextBox失去焦点:

<TextBox Name="txtRunAfter" Grid.Column="4" Text="{Binding RunAfter, UpdateSourceTrigger=PropertyChanged}" Style="{StaticResource TestStepTextBox}"/> 
+0

我想你对问题的评估是正确的,但调度员调用不起作用。我的UserControl在WinForm应用程序中使用ElementHost。这可能会影响分派器调用? – jpsstavares 2010-06-17 08:59:41

+0

好吧,我测试了这一点,它工作正常(当您从TextBox远离Tab键作为绑定的默认模式将不更新属性,直到TextBox失去焦点)。我更新了答案,以解释绑定上的UpdateSourceTrigger,以防您看到的行为。我对WinForms中托管的WPF没有太多处理,但我不明白为什么会影响您的上下文中的Binding或Dispatcher。 – 2010-06-17 14:22:29

3

有几件事情,我注意到这里。

除非您有充分的理由将RunAfter属性作为字符串公开,否则没有理由不能将它作为int。这可以节省你在setter中的强制转换(以及如果用户在字段中输入非整数内容时潜在的InvalidCastException)。

其次,OnPropertyChanged()调用应发生内部if语句以外,如下所示:在有条件的两个路径正在更新

if(_runAfter != val) 
{ 
    if(val < _order) 
     _runAfter = val; 
    else 
     _runAfter = 0; 
    OnPropertyChanged("RunAfter"); 
} 

由于_runAfter本地的,OnPropertyChanged()具有无论采取什么分支都会被调用。我希望这能帮助你指出正确的方向!

+0

+1指出的是,你需要移动OnPropertyChanged的其他外。 – Robaticus 2010-06-16 17:56:29

+0

那么,该视图通过视图调用(通过绑定),所以我认为只需要调用OnPropertyChanged,如果该值将从视图中设置的值更改。 – jpsstavares 2010-06-16 18:04:09

+0

无论如何,这并没有解决我的问题...... – jpsstavares 2010-06-16 18:05:37

1

我有同样的情况。我写了以下,它的工作。

<TextBox Grid.Column="3" Grid.Row="0" HorizontalAlignment="Left" VerticalAlignment="Center" Width="100" Text="{Binding Path=FirstName}"></TextBox>

而且

public string FirstName 
    { 
     get { return _client.FirstName; } 
     set 
     { 
      if (value == _client.FirstName) 
       return; 
      else 
       _client.FirstName = value; 
      OnPropertyChanged("FirstName"); 
     } 
    }