2010-05-12 22 views
21

Trong ứng dụng biểu mẫu cửa sổ, thay đổi thuộc tính kích hoạt INotifyPropertyChanged, sẽ dẫn đến biểu mẫu đọc EVERY thuộc tính từ đối tượng bị ràng buộc của tôi, không chỉ là thuộc tính đã thay đổi. (Xem mã ví dụ bên dưới).NET WinForms INotifyPropertyChanged cập nhật tất cả các ràng buộc khi một thay đổi. Cách tốt hơn?

Điều này có vẻ vô lý lãng phí vì giao diện yêu cầu tên của thuộc tính thay đổi. Nó đang gây ra rất nhiều thời gian trong ứng dụng của tôi vì một số getters thuộc tính yêu cầu tính toán được thực hiện.

Tôi có thể cần phải triển khai một số loại logic trong getters của mình để loại bỏ các lần đọc không cần thiết nếu không có cách nào tốt hơn để thực hiện việc này.

Tôi có thiếu gì đó không? Có cách nào tốt hơn? Đừng nói để sử dụng một công nghệ trình bày khác nhau xin vui lòng - Tôi đang làm điều này trên Windows Mobile (mặc dù hành vi xảy ra trên khuôn khổ đầy đủ là tốt).

Dưới đây là một số mã đồ chơi để chứng minh sự cố. Nhấp vào nút sẽ dẫn đến BOTH hộp văn bản được phổ biến ngay cả khi một thuộc tính đã thay đổi.

using System; 
using System.ComponentModel; 
using System.Drawing; 
using System.Windows.Forms; 

namespace Example 
{ 
public class ExView : Form 
{ 
    private Presenter _presenter = new Presenter(); 
    public ExView() 
    { 
     this.MinimizeBox = false; 

     TextBox txt1 = new TextBox(); 
     txt1.Parent = this; 
     txt1.Location = new Point(1, 1); 
     txt1.Width = this.ClientSize.Width - 10; 
     txt1.DataBindings.Add("Text", _presenter, "SomeText1"); 

     TextBox txt2 = new TextBox(); 
     txt2.Parent = this; 
     txt2.Location = new Point(1, 40); 
     txt2.Width = this.ClientSize.Width - 10; 
     txt2.DataBindings.Add("Text", _presenter, "SomeText2"); 

     Button but = new Button(); 
     but.Parent = this; 
     but.Location = new Point(1, 80); 
     but.Click +=new EventHandler(but_Click); 
    } 

    void but_Click(object sender, EventArgs e) 
    { 
     _presenter.SomeText1 = "some text 1"; 
    } 
} 

public class Presenter : INotifyPropertyChanged 
{ 

    public event PropertyChangedEventHandler PropertyChanged; 

    private string _SomeText1 = string.Empty; 
    public string SomeText1 
    { 
     get 
     { 
      return _SomeText1; 
     } 
     set 
     { 
      _SomeText1 = value; 
      _SomeText2 = value; // <-- To demonstrate that both properties are read 
      OnPropertyChanged("SomeText1"); 
     } 
    } 

    private string _SomeText2 = string.Empty; 
    public string SomeText2 
    { 
     get 
     { 
      return _SomeText2; 
     } 
     set 
     { 
      _SomeText2 = value; 
      OnPropertyChanged("SomeText2"); 
     } 
    } 

    private void OnPropertyChanged(string PropertyName) 
    { 
     PropertyChangedEventHandler temp = PropertyChanged; 
     if (temp != null) 
     { 
      temp(this, new PropertyChangedEventArgs(PropertyName)); 
     } 
    } 
} 

}

Trả lời

12

Lý do tại sao tất cả các thuộc tính đang được đọc khi sự kiện bị sa thải nằm trong phương pháp PushData kêu gọi các đối tượng ràng buộc khi sự kiện ProperyChanged là bắn. Nếu bạn nhìn vào stacktrace, bạn sẽ thấy rằng phương thức PropValueChanged của đối tượng nội bộ BindToObject được gọi, mà lần lượt gọi sự kiện Oncurrentchanged trên BindingManager. Cơ chế ràng buộc theo dõi các thay đổi của mục hiện tại, nhưng nó không làm phân biệt chi tiết hơn. Phương thức PushData "thủ phạm" gọi getter trên các thuộc tính của bạn (hãy xem mã bằng cách sử dụng bộ phản xạ). Vì vậy, không có cách nào xung quanh nó. Điều đó đang được nói, như quy tắc ngón tay cái, trong bộ tiếp cận nhận và đặt không được khuyến khích xử lý nặng, sử dụng các phương thức nhận và đặt riêng cho (nếu có thể)

Ngoài ra hãy xem bài viết này và nhận xét này đặc biệt (http://www.codeproject.com/Messages/2514032/How-Binding-watches-control-properties-i-e-how-doe.aspx), giải thích chính xác cách biến cố bất động sản được kích hoạt, mặc dù nó sẽ không giải quyết được vấn đề của bạn: http://www.codeproject.com/KB/database/databinding_tutorial.aspx?msg=2514032

Ý tưởng khám phá là trì hoãn getter được gọi. Bạn có thể đạt được điều này bằng cách chơi xung quanh với thuộc tính ControlUpdateMode của ràng buộc. Khi giá trị này được đặt thành Không bao giờ, điều khiển tương ứng sẽ không cập nhật khi có thay đổi. Tuy nhiên, khi bạn chuyển giá trị trở lại thành OnPropertyChanged, phương thức PushData sẽ được gọi, do đó các getters sẽ được truy cập. Vì vậy, xem xét ví dụ của bạn mã này sẽ tạm thời ngăn chặn sự textbox 2 để cập nhật:

void but_Click(object sender, EventArgs e) 
     {     
      txt2.DataBindings[0].ControlUpdateMode = ControlUpdateMode.Never; 
      _presenter.SomeText1 = "some text 1"; 
     } 
+0

Tôi đồng ý với mọi thứ bạn đã nói, tôi đã tìm thấy mã bạn đã đề cập trong Trình phản chiếu. Tôi sẽ đánh dấu câu trả lời của bạn là câu trả lời vì nó rất kỹ lưỡng và bạn xứng đáng được công nhận, tuy nhiên, sẽ tuyệt vời nếu bất kỳ ai khác thấy điều này có thể cung cấp các giải pháp thay thế bổ sung. BTW, đây là phương thức trong System.Windows.Forms.BindToObject để giảm thông tin thuộc tính notifcation ngay tại ranh giới giữa không gian tên đó và System.ComponentModel. Rực rỡ. riêng void PropValueChanged (đối tượng người gửi, EventArgs e) { this.bindingManager.OnCurrentChanged (EventArgs.Empty); } –

+0

@anchandra bạn nói: "_Khi giá trị này được đặt thành Không bao giờ, điều khiển tương ứng sẽ không cập nhật khi có thay đổi_". Chỉ để clearfi: 'DataSourceUpdateMode' xác định khi * Control * đẩy giá trị vào nguồn dữ liệu. Vì vậy, điều khiển sẽ vẫn cập nhật sau đó thay đổi thuộc tính nguồn dữ liệu. –

1

Tôi đang thử nghiệm subclassing ràng buộc như thế này và quản lý OnPropertyChanged, có thể giúp bạn.

public class apBinding : Binding 
{ 

     public apBinding(string propertyName, INotifyPropertyChanged dataSource, string dataMember) 
      : base(propertyName, dataSource, dataMember) 
     { 
      this.ControlUpdateMode = ControlUpdateMode.Never; 
      dataSource.PropertyChanged += new PropertyChangedEventHandler(OnPropertyChanged); 
     } 

     private void OnPropertyChanged(object sender, PropertyChangedEventArgs e) 
     { 

      if (e.PropertyName == this.BindingMemberInfo.BindingField) 
      { 
       this.ReadValue(); 
      } 
     } 
    } 

Bây giờ vấn đề mà tôi thấy là sự kiểm soát ghi đè giá trị của đối tượng liên quan, vì vậy tôi sửa đổi để

public class apBinding : Binding 
{ 

     public apBinding(string propertyName, INotifyPropertyChanged dataSource, string dataMember) 
      : base(propertyName, dataSource, dataMember) 
     { 

      dataSource.PropertyChanged += new PropertyChangedEventHandler(OnPropertyChanged); 
     } 

     private void OnPropertyChanged(object sender, PropertyChangedEventArgs e) 
     { 
      this.ControlUpdateMode = ControlUpdateMode.Never; 
      if (e.PropertyName == this.BindingMemberInfo.BindingField) 
      { 
       this.ReadValue(); 
      } 
     } 
    } 

thì propertychanges lần đầu tiên được gọi là tôi vô hiệu hóa controlupdate. và điều khiển được cập nhật chính xác ở lần chạy đầu tiên.

Các vấn đề liên quan