2009-01-26 29 views
6

Lúc đầu, tôi muốn nói rằng mẫu dưới đây là quá đơn giản. Giả sử bạn đã kiểm soát WPF bị ràng buộc.INotifyPropertyChanged problem

<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 được ràng buộc với lớp người mà thực hiện INotifyPropertyChanged và có Tên setter ở dạng

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

Tức là _name được gán "Some Name" bất cứ khi nào người dùng cố gắng thay đổi nó từ UI. Nhưng mẫu này không hoạt động. Tôi đã thay đổi tên trong TextBox thành một số giá trị nhấn tab buộc tiêu điểm để di chuyển đến nút và giá trị trong TextBox vẫn không thay đổi mặc dù sự kiện PropertyChanged đã được kích hoạt.

Bạn có thể giải thích tại sao điều đó xảy ra không? Theo tôi hiểu PropertyChanged sự kiện lực lượng giao diện người dùng để đọc lại các giá trị từ các thuộc tính và hiển thị chúng nhưng trong giá trị ví dụ của tôi trong hộp văn bản dữ liệu không được cập nhật.


Một lần nữa. Tôi hiểu rằng đây là việc thực hiện kém tài sản và tôi muốn lặp lại rằng đây là sự đơn giản hóa. Nó chỉ là một mẫu. Nhưng dù sao, PropertyChanged tín hiệu rằng tài sản đã được thay đổi và nên được cập nhật nhưng nó không.

+0

Err, tôi có thể sai, nhưng không nên nó được '{Binding Path = Tên}'? –

+1

Không. Đối với các ràng buộc thuộc tính, bạn có thể thoát khỏi Đường dẫn dưới dạng lối tắt. –

+1

Điều này là do Binding có một hàm khởi tạo lấy đường dẫn làm tham số. –

Trả lời

8

Sự kiện PropertyChanged bị bỏ qua bởi TextBox bởi vì nó là người khởi xướng sự kiện.

Một số làm rõ:

Các TextBox (hoặc bắt buộc đối với các textbox) biết nó là người khởi xướng bởi vì nó nhận được sự kiện PropertyChanged trong cuộc gọi tương tự. Bằng cách thực hiện cuộc gọi không đồng bộ, hộp văn bản (hoặc liên kết) không có cách nào để biết rằng đó là người khởi tạo, do đó, nó sẽ xử lý sự kiện như thể một người nào đó đã cập nhật sự kiện đó

Nếu bạn thêm hộp văn bản thứ 2 vào giao diện người dùng, bạn sẽ thấy rằng TextBox thứ 2 không thay đổi khi bạn chỉnh sửa số 1 và ngược lại.

+0

Nhưng tại sao cuộc gọi không đồng bộ hoạt động tốt? – Oleg

+0

Hộp văn bản (hoặc ràng buộc trên hộp văn bản) biết đó là trình khởi tạo vì nó nhận được sự kiện PropertyChanged trong cùng một cuộc gọi. Bằng cách thực hiện cuộc gọi không đồng bộ, hộp văn bản (hoặc liên kết) không có cách nào để biết rằng đó là người khởi tạo, do đó, nó sẽ xử lý sự kiện như thể ai đó đã cập nhật sự kiện – Bubblewrap

0

Lý do là vì bạn đã mã hóa cứng 'Tên một số' trong trình cài đặt. Khi bạn thay đổi giá trị textBox setter là thực sự nhận được gọi và nó một lần nữa thiết lập "Some Name" là propertyValue vì vậy nó doesnt dường như được thay đổi trong giao diện người dùng. Đặt _name = value và mọi thứ sẽ hoạt động như bạn mong đợi,

+0

Tôi nghĩ rằng OP thực sự muốn giá trị tài sản là "Một số tên" mỗi khi ai đó thay đổi giá trị, bất kể những gì họ nhập. – matrixugly

0

Nếu tôi không nhầm, hành vi ràng buộc mặc định của thuộc tính Văn bản trên TextBox là TwoWay, vì vậy điều này sẽ hoạt động. Bạn có thể ép buộc nó là TwoWay trong XAML như sau:

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

Lưu ý Mode=TwoWay trong khai báo Ràng buộc.

Nếu điều đó không có tác dụng, thì tôi nghi ngờ rằng một ngoại lệ sẽ bị ném vào mã kích hoạt sự kiện hoặc gán thuộc tính và bạn nên tìm kiếm điều đó.


Có vẻ như bạn đang thực hiện cuộc gọi để thay đổi giá trị trên chuỗi không phải là chuỗi giao diện người dùng. Nếu đây là trường hợp, thì bạn phải sắp xếp cuộc gọi để kích hoạt sự kiện đã thay đổi thuộc tính trên chuỗi giao diện người dùng hoặc thực hiện thay đổi đối với giá trị trên chuỗi giao diện người dùng.

Khi đối tượng bị ràng buộc với phần tử giao diện người dùng, các thay đổi đối tượng có thể ảnh hưởng đến giao diện người dùng phải được thực hiện trên chuỗi giao diện người dùng.

0
public string MyField 
{ 
    get { return _myField; } 
    set { 
     if (_myField == value) 
      return; 

     _myField = value; 

     OnPropertyChanged("MyField"); 
    } 
} 

Đây là việc triển khai đúng thuộc tính.

Khi bạn thay đổi thuộc tính, hãy đảm bảo rằng ví dụ giống hệt nhau của đối tượng được liên kết với điều khiển. Nếu không, thay đổi sẽ được thông báo nhưng điều khiển sẽ không bao giờ nhận được nó bởi vì điều khiển không bị ràng buộc đúng cách.

0

Thay setter ở dạng

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

giải quyết vấn đề này nhưng nó vẫn còn mở. Tại sao tôi nên thực hiện cuộc gọi không đồng bộ thay vì báo hiệu đồng bộ rằng thuộc tính của tôi đã bị thay đổi.

2

Như Bubblewrap đã chỉ ra, điều này là do thiết kế - hộp văn bản giả định rằng nếu nó đặt thuộc tính bị ràng buộc thành một giá trị nào đó, trình thiết lập sẽ không thay đổi giá trị. According to Microsoft, họ sẽ không thay đổi hành vi này vì điều này sẽ phá vỡ mã hiện tại.

Nếu bạn muốn để thay đổi giá trị (có, có lý do chính đáng để làm điều đó), bạn phải sử dụng giải pháp thay thế bằng cách thêm trình chuyển đổi giả. Có a blog entry (không phải do tôi viết) mô tả kỹ thuật này một cách chi tiết.

4

Bộ chuyển đổi workaround giả đề xuất bởi Heinzi (mô tả here) không hoạt động khi ràng buộc của UpdateSourceTriggerPropertyChanged. Nhưng nếu đây là những gì chúng ta cần?

Dường như làm cho asynchrounous ràng buộc hiện các trick, ví dụ .:

SelectedIndex="{Binding SelectedIndex, IsAsync=True}"