2010-08-17 3 views
2

컨트롤에 바인딩하려는 사용자 지정 개체가 있습니다. 해당 사용자 정의 객체에서 INotifyPropertyChanged 인터페이스를 구현했습니다. 내 개체와 그 개체의 속성에 성공적으로 바인딩되었습니다.WPF/XAML에서 INotifyPropertyChanged를 올바르게 사용하는 방법

내가 알 수없는 것은 거기에서 어떻게 가는지입니다. 나는 2 일 동안이 작업을하고 있었지만 아직 작동시키지 못하고있다.

내 가정은 컨트롤에 바인딩 된 속성을 변경하면 해당 속성에 설정된 값이 컨트롤에 나타날 것입니다. 그러나 아무리 많은 속성을 변경하더라도 UI는 초기 값 이상으로 업데이트되지 않습니다. 나는이 방식에서 INotifyPropertyChanged를 구현 한

는 : 는 A base class which implements INotifyPropertyChanged

그래서 내 기본 클래스는 이것이다 :

[Serializable] 
public abstract class BindableObject : INotifyPropertyChanged 
{ 
    #region Data 

    private static readonly Dictionary<string, PropertyChangedEventArgs> eventArgCache; 
    private const string ERROR_MSG = "{0} is not a public property of {1}"; 

    #endregion // Data 

    #region Constructors 

    static BindableObject() 
    { 
     eventArgCache = new Dictionary<string, PropertyChangedEventArgs>(); 
    } 

    protected BindableObject() 
    { 
    } 

    #endregion // Constructors 

    #region Public Members 

    /// <summary> 
    /// Raised when a public property of this object is set. 
    /// </summary> 
    [field: NonSerialized] 
    public event PropertyChangedEventHandler PropertyChanged; 

    /// <summary> 
    /// Returns an instance of PropertyChangedEventArgs for 
    /// the specified property name. 
    /// </summary> 
    /// <param name="propertyName"> 
    /// The name of the property to create event args for. 
    /// </param> 
    public static PropertyChangedEventArgs 
     GetPropertyChangedEventArgs(string propertyName) 
    { 
     if (String.IsNullOrEmpty(propertyName)) 
      throw new ArgumentException(
       "propertyName cannot be null or empty."); 

     PropertyChangedEventArgs args; 

     // Get the event args from the cache, creating them 
     // and adding to the cache if necessary. 
     lock (typeof(BindableObject)) 
     { 
      bool isCached = eventArgCache.ContainsKey(propertyName); 
      if (!isCached) 
      { 
       eventArgCache.Add(
        propertyName, 
        new PropertyChangedEventArgs(propertyName)); 
      } 

      args = eventArgCache[propertyName]; 
     } 

     return args; 
    } 

    #endregion // Public Members 

    #region Protected Members 

    /// <summary> 
    /// Derived classes can override this method to 
    /// execute logic after a property is set. The 
    /// base implementation does nothing. 
    /// </summary> 
    /// <param name="propertyName"> 
    /// The property which was changed. 
    /// </param> 
    protected virtual void AfterPropertyChanged(string propertyName) 
    { 
    } 

    /// <summary> 
    /// Attempts to raise the PropertyChanged event, and 
    /// invokes the virtual AfterPropertyChanged method, 
    /// regardless of whether the event was raised or not. 
    /// </summary> 
    /// <param name="propertyName"> 
    /// The property which was changed. 
    /// </param> 
    protected void RaisePropertyChanged(string propertyName) 
    { 
     this.VerifyProperty(propertyName); 

     PropertyChangedEventHandler handler = this.PropertyChanged; 
     if (handler != null) 
     { 
      // Get the cached event args. 
      PropertyChangedEventArgs args = 
       GetPropertyChangedEventArgs(propertyName); 

      // Raise the PropertyChanged event. 
      handler(this, args); 
     } 

     this.AfterPropertyChanged(propertyName); 
    } 

    #endregion // Protected Members 

    #region Private Helpers 

    [Conditional("DEBUG")] 
    private void VerifyProperty(string propertyName) 
    { 
     Type type = this.GetType(); 

     // Look for a public property with the specified name. 
     PropertyInfo propInfo = type.GetProperty(propertyName); 

     if (propInfo == null) 
     { 
      // The property could not be found, 
      // so alert the developer of the problem. 

      string msg = string.Format(
       ERROR_MSG, 
       propertyName, 
       type.FullName); 

      Debug.Fail(msg); 
     } 
    } 

    #endregion // Private Helpers 
} 

내가 위에 내가 내 재산에 이렇게 내 파생 클래스에서 그 클래스에서 상속 :

public virtual string Name 
    { 
     get 
     { 
      return m_strName; 
     } 
     set 
     { 
      m_strName = value; 
      RaisePropertyChanged("Name"); 
     } 
    } 

내 XAML이 (축약 버전)과 같습니다

<Window x:Class="PSSPECApplication.Windows.Project" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:System="clr-namespace:System;assembly=mscorlib" 
    DataContext="{Binding SizingProject, RelativeSource={RelativeSource Self}}"> 
     <StackPanel VerticalAlignment="Center"> 
      <TextBox Name="txtProjectName" Text="{Binding Name}" /> 
     </StackPanel> 

창의 데이터 컨텍스트가 SizingProject라는 속성임을 알 수 있습니다. SizingProject는 BindableObject에서 파생 된 파생 형식이며 Name 속성이 들어 있으며 PropertyChanged 이벤트 처리기를 발생시킵니다.

내 창 생성자에서 SizingProject를 채우고 Name 속성이 설정됩니다.

테스트하려면이 창에 이름 속성을 원래대로 설정하는 이벤트를 발생시키는 단추가 있어야합니다. 그러나 name 속성이 변경되면 아무 일도 일어나지 않습니다. BindableObject로 추적했고 PropertyChanged 이벤트는 항상 null로 설정되므로 처리기가 설정되고 실행되지 않습니다. 왜 이런거야?

나는 INotifyPropertyChanged를 구현하고 해당 유형의 바인딩을 사용하여 WPF가 해당 이벤트 핸들러를 자동으로 설정 한 다음 올바른 동작이 발생한다고 생각했습니다. 나를 위해, 나는 그 행동을 결코 보지 못한다.


나는이 문제를 파악했다. 내가해야 할 일은 SizingProject 속성에 대한 DependencyProperty를 만드는 것입니다. 내가 그 일을 끝내고 모든 일이 잘 됐어.

 public static readonly DependencyProperty SizingProjectProperty = 
     DependencyProperty.Register("SizingProject", typeof(Sizing.Project), typeof(Project), new UIPropertyMetadata()); 

    public Sizing.Project SizingProject 
    { 
     get 
     { 
      return (Sizing.Project)GetValue(Project.SizingProjectProperty); 
     } 
     set 
     { 
      SetValue(Project.SizingProjectProperty, value); 
     } 
    } 
+0

출력 창에 바인딩 오류가 있습니까? –

+0

대신이 솔루션을 대신 사용해야했습니다. http://www.pochet.net/blog/2010/07/02/inotifypropertychanged-automatic-dependent-property-and-nested-object-support/ – Ristogod

답변

3

내 컴퓨터에서 작동합니다. 하지만 캐시는 일종의 괴상한 것입니다. 나는 형식 당 정적 읽기 전용 버전을 만들거나 필요할 때까지 캐싱에 대해 잊어 버렸습니다 (조기 최적화 및 모두).

샘플 프로젝트를 만들었습니다. 나는 내가 XAML에서 생성을 MyObject의 인스턴스에 바인딩하고있어

<Window x:Class="INPCTest.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:this="clr-namespace:INPCTest" 
     Title="MainWindow" Height="350" Width="525"> 
    <Window.DataContext> 
     <this:MyObject /> 
    </Window.DataContext> 
    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition /> 
      <RowDefinition /> 
     </Grid.RowDefinitions> 
     <TextBlock 
      Text="{Binding MyOutProperty}" /> 
     <TextBox 
      Grid.Row="1" 
      Text="{Binding MyInProperty, UpdateSourceTrigger=PropertyChanged}" /> 
    </Grid> 
</Window> 

(이 당신에게 익숙한 것이 아닌 경우에는 코드 숨김에서이 ​​작업을 수행 할 수 있습니다) : 메인 윈도우는 다음과 같습니다.

class MyObject : BindableObject 
{ 
    private string _in; 
    private string _out; 
    public string MyOutProperty 
    { 
     get { return _out; } 
     set { _out = value; this.RaisePropertyChanged("MyOutProperty"); } 
    } 
    public string MyInProperty 
    { 
     get { return _in; } 
     set 
     { 
      _in = value; 
      MyOutProperty = "The textbox below says: \"" + value + "\""; 
      this.RaisePropertyChanged("MyInProperty"); 
     } 
    } 
} 

모두가 함께 작동 얼마나 : MyObject를이 Window.DataContext

  • 인스턴스화 및 설정
  • 인스턴스

    1. 윈도우를 만든 다음

      는 MyObject를위한 코드입니다 TextBlock이 에 바인딩 됨 MyOutProperty
    2. 텍스트 상자가 MyInProperty에 바인딩
    3. 는 사용자
    4. MyInProperty이 'X'
    5. MyOutProperty '로 설정되어 설정되어있는 텍스트 상자에서 유형'X '는 텍스트 상자 아래 말한다 : " X MyOutProperty "
    6. " '
    7. MyOutProperty의 설정 방법은 호출 는 전달을 RaisePropertyChanged "3210
    8. TextBlock이 예상대로 업데이트됩니다.

    문제가 기본 클래스와 다르다고 생각됩니다. 하위 클래스 구현 또는 바인딩 중 하나입니다.

    바인딩을 디버깅하는 데 도움이되도록 follow the information at this link은 Visual Studio에 장황한 바인딩 추적 출력을 구성합니다 (구성한 경우 출력 창 또는 직접 실행 창에서 종료 됨).

  • +0

    이미 인스턴스화 된 개체의 속성에 바인딩하려고합니다. 인스턴스화 된 객체는 Window 코드의 속성에서 참조됩니다. 구문 중 일부를 시도했지만 DataContext 부분에서 매개 변수를 사용하지 않는 생성자가없는 개체에 바인딩한다고 말합니다. 나는 새로운 대상에 묶고 싶지 않습니다. 나는 이미 존재하는 것에 묶으려고 노력하고있다. – Ristogod

    +0

    내가 문제를 알았지 만, 당신이 도우려고했던 유일한 사람이기 때문에 어쨌든 당신에게 크레딧을 줬습니다. 감사. – Ristogod

    +0

    @rist 그래서 문제가 무엇입니까? – Will