2010-06-16 37 views
6

Tôi có một TextBox có giá trị gia tăng bị ràng buộc với một tài sản ViewModel:WPF giá trị TextBox không thay đổi trên OnPropertyChanged

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

Tập và nhận đang làm việc tốt cho đến khi tôi đã cố gắng để thêm một số xác nhận khi giá trị là set:

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"); 
       } 
      } 
     } 
    } 

Mặc dù OnPropertyChanged đã đạt đến (tôi đã lồng tiếng), Chế độ xem không thay đổi. Tôi có thể thực hiện công việc này bằng cách nào?

Xin cảm ơn, José Tavares

Trả lời

5

Sự cố là bạn đang cập nhật nguồn cho số Binding trong khi Binding đang cập nhật thuộc tính của bạn. WPF sẽ không thực sự kiểm tra giá trị tài sản của bạn khi nó làm tăng sự kiện PropertyChanged để đáp ứng bản cập nhật Binding. Bạn có thể giải quyết điều này bằng cách sử dụng Dispatcher để trì hoãn việc tuyên truyền về sự kiện này tại chi nhánh:

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"); 
     } 
    } 
} 

Cập nhật:

Một điều khác tôi nhận thấy là các Binding trên TextBox bạn đang sử dụng mặc định UpdateSourceTrigger, điều này xảy ra khi số TextBox mất tiêu điểm. Bạn sẽ không thấy thay đổi văn bản quay lại 0 cho đến sau khi TextBox mất tiêu điểm với chế độ này. Nếu bạn thay đổi nó thành PropertyChanged, bạn sẽ thấy điều này xảy ra ngay lập tức. Nếu không, thuộc tính của bạn sẽ không được đặt cho đến khi số TextBox mất tiêu điểm:

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

Tôi đoán đánh giá của bạn về vấn đề là chính xác, nhưng cuộc gọi điều phối không hoạt động. My UserControl được sử dụng bên trong một ứng dụng WinForm bằng cách sử dụng một ElementHost. Có thể điều này ảnh hưởng đến cuộc gọi Dispatcher? – jpsstavares

+0

Được rồi, tôi đã thử nghiệm điều này và nó hoạt động tốt (khi bạn thoát khỏi TextBox là chế độ mặc định của liên kết sẽ không cập nhật thuộc tính cho đến khi TextBox mất tiêu điểm). Tôi đã cập nhật câu trả lời để giải thích về UpdateSourceTrigger về các ràng buộc, trong trường hợp đó là hành vi mà bạn đang thấy. Tôi không giải quyết rất nhiều với WPF được lưu trữ trong WinForms, nhưng tôi không thấy lý do tại sao điều đó sẽ ảnh hưởng đến Binding hoặc Dispatcher trong ngữ cảnh của bạn. –

3

Một vài điều tôi nhận thấy ở đây.

Trừ khi bạn có lý do thuyết phục để hiển thị thuộc tính RunAfter dưới dạng chuỗi, không có lý do gì khiến nó không thể là int. Điều đó sẽ giúp bạn tiết kiệm các diễn viên trong setter (cũng như một ẩn có thể InvalidCastException nếu người dùng nhập một cái gì đó không số nguyên trong lĩnh vực này).

Thứ hai, OnPropertyChanged() gọi nên xảy ra bên ngoài khu vực nội câu lệnh if, giống như sau:

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

Kể từ khi _runAfter địa phương đang được cập nhật trong cả đường dẫn của điều kiện, OnPropertyChanged() có được gọi là bất kể nhánh nào được lấy. Tôi hy vọng rằng sẽ giúp bạn đi đúng hướng!

+0

+1 cho lưu ý rằng bạn cần phải di chuyển OnPropertyChanged bên ngoài khác. – Robaticus

+0

Vâng, tập hợp được gọi là Xem (qua ràng buộc) vì vậy tôi nghĩ rằng nó sẽ chỉ cần thiết để gọi OnPropertyChanged nếu giá trị sẽ được thay đổi từ một trong những setted trong View. – jpsstavares

+0

Dù sao, điều đó không giải quyết được vấn đề của tôi ... – jpsstavares

1

Tôi có cùng hoàn cảnh. Tôi đã viết như sau và nó đã hoạt động.

<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"); 
     } 
    } 
Các vấn đề liên quan