2010-05-12 2 views
21

Windows 양식 응용 프로그램에서 INotifyPropertyChanged를 트리거하는 속성 변경으로 인해 속성이 변경된 것이 아니라 바인딩 된 개체에서 모든 속성을 읽는 형식이됩니다. 아래의 예제 코드를 참조하십시오..NET WinForms INotifyPropertyChanged는 모든 바인딩이 변경되면이를 업데이트합니다. 더 좋은 방법?

인터페이스에 변경 속성의 이름이 필요하기 때문에 이것은 터무니 없게 보입니다. 일부 속성 getter는 계산을 수행해야하기 때문에 응용 프로그램에서 많은 시간을 차지하게됩니다.

내 게터에 일종의 로직을 구현하여 더 좋은 방법이 없다면 불필요한 읽기를 버릴 수도 있습니다.

나는 뭔가를 놓친가요? 더 좋은 방법이 있습니까? 다른 프리젠 테이션 기술을 사용하라고 말하지 마십시오. Windows Mobile에서이 작업을 수행하고 있습니다 (전체 프레임 워크에서도 문제가 발생 함).

다음은 장난감 코드로 문제를 보여줍니다. 버튼을 클릭하면 하나의 속성이 변경 되더라도 두 텍스트 상자가 채워집니다.

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

}

답변

12

이유 왜 ProperyChanged의 이벤트가 발생할 때 트리거됩니다 이벤트가 바인딩 개체에서 호출 PushData 방법에 달려있다 할 때 모든 속성을 읽을 수 있습니다. stacktrace를 살펴보면 내부 객체 BindToObject의 PropValueChanged 메서드가 호출되고 BindingManager에서 Oncurrentchanged 이벤트가 차례로 호출된다는 것을 알 수 있습니다. 바인딩 메커니즘은 현재 항목 변경 사항을 추적하지만보다 세분화 된 구분은하지 않습니다. "범인"PushData 메서드는 속성에서 getter를 호출합니다 (반사자를 사용하여 코드를 살펴보십시오). 따라서 주위에는 방법이 없습니다. 즉, get 및 set 접근자는 무거운 처리를 권장하지 않습니다. 가능한 경우 별도의 get 및 set 메서드를 사용하십시오 (가능한 경우)

또한이 기사를 살펴보고 이 코멘트 (특히 http://www.codeproject.com/Messages/2514032/How-Binding-watches-control-properties-i-e-how-doe.aspx)는 getter 문제를 해결하지는 않지만 propertychanged 이벤트가 어떻게 발생하는지 정확하게 설명합니다. http://www.codeproject.com/KB/database/databinding_tutorial.aspx?msg=2514032

탐색 할 아이디어는 호출되는 getter를 지연하는 것입니다. 바인딩의 ControlUpdateMode 속성을 사용하여이 작업을 수행 할 수 있습니다. 이 값을 Never로 설정하면 변경 사항이있을 때 해당 컨트롤이 업데이트되지 않습니다. 그러나 값을 다시 OnPropertyChanged로 전환하면 PushData 메서드가 호출되어 getters에 액세스하게됩니다. 그래서 예를 고려하고이 코드가 일시적으로 업데이트 할 텍스트 상자 (2)를 방지 할 수 있습니다 :

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

나는 당신이 말한 모든 것에 동의합니다. 나는 당신이 반사경에서 언급 한 코드를 발견했습니다. 답변을 답변으로 표시하려고합니다. 왜냐하면 매우 철저하므로 인정을받을 자격이 있지만, 다른 사람이 다른 대안을 제시 할 수 있다면 좋을 것입니다. 여기에 System.Windows.Forms.BindToObject의 메서드는 해당 네임 스페이스와 System.ComponentModel 사이의 경계에서 알 림 속성 정보를 삭제합니다. 훌륭한. private void PropValueChanged (개체 보낸 사람, EventArgs e) { this.bindingManager.OnCurrentChanged (EventArgs.Empty); } –

+0

@anchandra 당신은 이렇게 말합니다. "_이 값을 사용하지 않으면 해당 컨트롤이 변경 될 때 업데이트되지 않습니다." 그냥 clearfi :'DataSourceUpdateMode'는 * Control *이 값을 데이터 소스에 푸시 다운 할 때를 결정합니다. 따라서 컨트롤은 여전히 ​​데이터 소스 속성 변경 사항을 업데이트합니다. –

1

을 나는이 같은 바인딩 및 OnPropertyChanged를 관리 서브 클래스 테스트하고있어, 어쩌면 당신을 도와줍니다.

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

지금은 컨트롤이 연결된 개체의 값을 덮어 씁니다 찾을 문제는, 는 그래서 난 후 처음 propertychanges 내가 controlupdate을 해제라고

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

로 수정했습니다. 컨트롤은 첫 번째 실행시 올바르게 업데이트됩니다.

관련 문제