2012-07-27 2 views
2

제가 배우는 중 ... 데이터 조각에 대해 잘 작동하는 간단한 데이터 바인딩 프로젝트를 만들었습니다. 이름. 그러나, 나는이 lastName 컴파일러를 사용하려고하고있을 때하면 현재 스레드가 스택 오버 플로우 상태에 있기 때문에 식을 계산할 수 없습니다현재 스레드가 스택 오버 플로우 상태에 있기 때문에 표현식을 평가할 수 없습니다

**와 같은 런타임 오류가 발생합니다. **

이 코드입니다. 두 번째 필드 (성)가 스택 오버플로를 일으키고 있기 때문에 주석으로 처리됩니다. 모든 의견을 부탁드립니다.

public partial class MainWindow : Window 
{ 
    Person p; 

    public MainWindow() 
    { 
     InitializeComponent(); 

     p = new Person(); 
     p.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(p_PropertyChanged); 

     this.DataContext = p; 

     p.FirstName = p.OriginalFirstName; 
     p.LastName = p.OriginalLastName; 
    } 

    void p_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) 
    { 
     stat1.Text = (p.OriginalFirstName == p.FirstName) ? "Original" : "Modified"; 
     //stat2.Text = (p.OriginalLastName == p.LastName) ? "Original" : "Modifined"; 
    } 

} 

편집 :

class Person : INotifyPropertyChanged 
    { 

     public string OriginalFirstName = "Jim"; 
     public string OriginalLastName = "Smith"; 

     private string _firstName; 

     #region FirstName 
     public string FirstName 
     { 
      get { return _firstName; } 
      set 
      { 
       if (value != null) 
       { 
        _firstName = value; 
        NotifyTheOtherGuy(FirstName); 
       } 
      } 
     } 
     #endregion FirstName 

     private string _lastName; 

     #region LastName 
     public string LastName 
     { 
      get { return _lastName; } 
      set 
      { 
       if (value != null) 
       { 
        _lastName = value; 
        NotifyTheOtherGuy(LastName); 
       } 
      } 
     } 
     #endregion LastName 

     public Person() 
     { 

     } 

     public event PropertyChangedEventHandler PropertyChanged; 
     void NotifyTheOtherGuy(string msg) 
     { 
      if (PropertyChanged != null) 
      { 
       PropertyChanged(this, new PropertyChangedEventArgs(msg)); 
      } 

     } 

    } 

XAML :

<Window x:Class="FullNameDataBinding.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="Auto"/> 
      <RowDefinition Height="Auto"/> 
     </Grid.RowDefinitions> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="100"/> 
      <ColumnDefinition Width="100"/> 
      <ColumnDefinition Width="100"/> 
     </Grid.ColumnDefinitions> 

     <Label Grid.Column="0" Grid.Row="0" Content="First Name:"/> 
     <Label Grid.Row="1" Content="Last Name:"/> 
     <TextBox Grid.Column="1" Grid.Row="0" Background="Yellow" Margin="5" FontWeight="Bold" Text="{Binding Path=FirstName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> 
     <TextBlock x:Name="stat1" Grid.Column="2" /> 
     <TextBox x:Name="stat2" Grid.Column="1" Grid.Row="1" Background="Yellow" Margin="5" FontWeight="Bold" Text="{Binding Path=LastName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> 
     <TextBlock Grid.Column="2" Grid.Row="1" /> 
    </Grid> 
</Window> 
+0

'Person' 클래스를 게시 할 수 있습니까? 편집 : 또한, 귀하의'stat1'과'stat2' 텍스트 필드가 그 사람에게 묶여 있습니까? –

+0

또한 WPF 컨트롤에 대한 XAML을 게시하십시오. XAML을 사용하여 올바른 컨텍스트에 바인딩하면이 모든 문제가 해결됩니다 ... – EtherDragon

+0

감사합니다. 방금 Person 클래스를 추가했습니다. stat1 및 stat2는 TextBlocks입니다. –

답변

4

나는 당신의 XAML의이 덩어리에서 오류를 생각 :

<TextBox Grid.Column="1" Grid.Row="0" Background="Yellow" Margin="5" FontWeight="Bold" Text="{Binding Path=FirstName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> 
    <TextBlock x:Name="stat1" Grid.Column="2" /> 
    <TextBox x:Name="stat2" Grid.Column="1" Grid.Row="1" Background="Yellow" Margin="5" FontWeight="Bold" Text="{Binding Path=LastName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> 
    <TextBlock Grid.Column="2" Grid.Row="1" /> 

난 당신이 마지막 TextBlock가 이전 x:Name="stat2" 아닌 TextBox을 갖고 싶어 생각합니다.

LastName을 변경하면 stat2의 텍스트 값을 변경하는 PropertyChanged 이벤트 처리기가 호출됩니다. stat2TwoWay 바인딩을 사용하여 값이 LastName에 바인딩 된 TextBox이므로 바인딩 메커니즘이 설정 한 값을 다시 뷰 모델에 보냅니다. 이로 인해 또 다른 PropertyChanged 이벤트가 발생하여 stat2 값이 변경되어 다른 PropertyChanged 이벤트가 발생합니다.이 끝없는주기가 중지되지 않으므로 스택 오버플로 오류가 발생합니다.

FirstName과 함께 스택 오버플로가 발생하지 않으므로 stat1Text 속성에 바인딩이없는 TextBlock이므로 바인딩 오버플로가 발생하지 않습니다.

+0

감사합니다. Luke. 당신 말이 맞습니다. 태그 사이를 뛰어 넘으면 어디에서 이름을 추가하는지 잊어 버렸습니다. 큰 도움이되었습니다. –

1

속성이 변경 될 때마다, 당신은 속성 (텍스트 값)을 변경 다른 프로퍼티 변경 이벤트를 해제 발사하는 텍스트 속성을 변경합니다 ....

이 부분이 어떻게 될지 알고 계십니까?

텍스트 속성을 변경할 때 이벤트 실행을 비활성화하거나 속성이 변경된 이벤트 처리기의 컨텍스트에서 이벤트 속성을 변경해야합니다.

Person 클래스의 세부 정보가 없기 때문에 이벤트 실행을 중지하거나 이벤트를 실행하지 않고 값을 변경하기위한 메커니즘을 이미 지원하는지 여부는 알 수 없습니다. 하나도 존재하지 않는다면 자신 만의 템플릿을 만들어야 할 수도 있습니다. 그렇게하는 방법은 해당 클래스의 구현에 따라 달라집니다.

0

p_PropertyChanged 메서드는 정적이어야하며 메서드에 대한 다음 변경 내용은 문제없이 작동 할 수 있다고 가정합니다.

static void p_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) 
{ 
    MainWindow w = (MainWindow) sender; 
    w.stat1.Text = (w.p.OriginalFirstName == w.p.FirstName) ? "Original" : "Modified"; 
    //stat2.Text = (p.OriginalLastName == p.LastName) ? "Original" : "Modifined"; 
} 

있지만 XAML 코드의 일부를 게시 할 경우 당신은 아마 깨끗한 방법으로 같은 결과를 얻을 수 있기 때문에 더 나은 것입니다.

WPF로 작업 할 때 winform 프로그래밍 코드 실습을 거의 잊어 버려야합니다. 주로 Bindings 및 DependenciesProperty를 사용하여 코드를 작성해야한다고 가정합니다.

편집

  1. 다른 사람이 당신은 아마 잘못된 객체에 STAT1 이름을 할당이가있는 StackOverflowException을 던져 무한 재귀를 시작 말했듯이.
  2. Person 클래스에서 PropertyChanged는 해당 값이 아닌 속성 이름과 함께 호출되어야합니다.

다음은이 문제로 인해 멈추지 않는 작업 샘플을 보여 주며 WPF 플랫폼을 사용하여 View 클래스에서 모든 주요 정교 작업을 끌어 와서 이동하도록 허용하고 싶습니다. 단계 MVVM 패러다임

Person 클래스에는 Check 속성이 추가되었습니다. 예외를 실행 한 원래의 속성 변경된 메서드의 조건을 평가합니다. CheckFirstName 또는 CheckLastName 변경에 대한 이벤트가 변경되면 FirstName 또는 LastName 속성이 변경됩니다.이 방법으로 조건의 평가가이 모델 클래스에 의해 이미 완료되고 결과가 사용 가능하고 바운드 오브젝트에 대해 준비되기 때문에이 목적으로 View 클래스에서 변경 이벤트를 처리 할 필요가 없습니다.

public class Person : INotifyPropertyChanged 
{ 

    public string OriginalFirstName = "Jim"; 
    public string OriginalLastName = "Smith"; 

    private string _firstName; 

    #region FirstName 
    public string FirstName 
    { 
     get { return _firstName; } 
     set 
     { 
      if (value != null) 
      { 
       _firstName = value; 
       NotifyTheOtherGuy("CheckFirstName"); 
      } 
     } 
    } 
    #endregion FirstName 

    private string _lastName; 

    #region LastName 
    public string LastName 
    { 
     get { return _lastName; } 
     set 
     { 
      if (value != null) 
      { 
       _lastName = value; 
       NotifyTheOtherGuy("CheckLastName"); 
      } 
     } 
    } 
    #endregion LastName 


    public string CheckFirstName 
    { 
     get 
     { 
      return (FirstName==OriginalFirstName) ? "Original": "Modified"; 
     } 
    } 
    public string CheckLastName 
    { 
     get 
     { 
      return (LastName==OriginalLastName) ? "Original": "Modified"; 
     } 
    } 

    public Person() 
    { 

    } 

    public event PropertyChangedEventHandler PropertyChanged; 
    void NotifyTheOtherGuy(string msg) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(msg)); 
     } 

    } 

} 

MainWindow를 클래스 : 모든 정교화 작업이 클래스에서 제거되고 Person 객체에 대한 DependecyProperty의 정의가있다.

public partial class MainWindow : Window 
{ 
    public static readonly DependencyProperty MyPersonProperty; 
    static MainWindow() 
    { 
     MyPersonProperty = DependencyProperty.Register("MyPerson", typeof(Person), typeof(MainWindow)); 
    } 
    Person MyPerson 
    { 
     set 
     { 
      SetValue(MyPersonProperty,value); 
     } 
     get 
     { 
      return GetValue(MyPersonProperty) as Person; 
     } 
    } 
    public MainWindow() 
    { 
     MyPerson = new Person(); 

     InitializeComponent(); 
    } 
} 

MainWindow XAML : 각 구성 요소는 올바른 방식으로 Person DependencyProperty에 바인딩됩니다. TextBoxes는 Person 속성 값을 업데이트하도록 바인딩되고 TextBlock은 Person 클래스의 다른 속성이 변경된 후에 변경 내용을 알리는 Check 속성의 결과를 가져 오도록 바인딩됩니다.

<?xml version="1.0" encoding="utf-8"?> 
<Window 
    x:Class="TryPrj.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:prj="clr-namespace:TryPrj" 
    Title="TryPrj" 
    Height="300" 
    Width="300" 
    x:Name="myWindow"> 
    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition 
       Height="Auto" /> 
      <RowDefinition 
       Height="Auto" /> 
     </Grid.RowDefinitions> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition 
       Width="100" /> 
      <ColumnDefinition 
       Width="100" /> 
      <ColumnDefinition 
       Width="100" /> 
     </Grid.ColumnDefinitions> 
     <Label 
      Grid.Column="0" 
      Grid.Row="0" 
      Content="First Name:" /> 
     <Label 
      Grid.Row="1" 
      Content="Last Name:" /> 
     <TextBox 
      Grid.Column="1" 
      Grid.Row="0" 
      Background="Yellow" 
      Margin="5" 
      FontWeight="Bold" 
      Text="{Binding Path=MyPerson.FirstName, Mode=OneWayToSource, ElementName=myWindow, UpdateSourceTrigger=PropertyChanged}" /> 
     <TextBlock 
      Grid.Column="2" 
      Text="{Binding Path=MyPerson.CheckFirstName, Mode=OneWay, ElementName=myWindow}" 
     /> 
     <TextBox 
      Grid.Column="1" 
      Grid.Row="1" 
      Background="Yellow" 
      Margin="5" 
      FontWeight="Bold" 
      Text="{Binding Path=MyPerson.LastName, Mode=OneWayToSource, ElementName=myWindow, UpdateSourceTrigger=PropertyChanged}" /> 
     <TextBlock 
      Grid.Column="2" 
      Grid.Row="1" 
      Text="{Binding Path=MyPerson.CheckLastName, Mode=OneWay, ElementName=myWindow}" /> 
    </Grid> 
</Window> 
+0

이 변경을하면 같은 결과가 발생합니다. 속성 변경 이벤트에서 속성을 계속 변경하고 있으므로 무한 재귀가 발생합니다. – Servy

+0

Person을 변경하는 메소드에 의해 stat1.TextChanged가 처리 될 때만 발생할 수 있습니다. 그 영업권으로 그런 것이 있었나요? 당신은 다른 방법을 알고 있습니까? 나는 XAML 코드를 볼 필요가 있다고 가정한다. –

+0

xaml과 Person 클래스를 모두 게시했습니다. ** 정적 ** 시도했지만 컴파일러는 그것에 대해 행복하지 않았습니다. –

관련 문제