2012-07-27 43 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

你可以發佈你的'人'類嗎?編輯:另外,你的'stat1'和'stat2'文本域綁定到這個人? – 2012-07-27 19:19:55

+0

也發佈您的WPF控件的XAML。使用XAML綁定到正確的上下文修復了所有這些... – EtherDragon 2012-07-27 19:47:01

+0

感謝所有。我剛添加Person類。 stat1和stat2是TextBlocks – 2012-07-27 21:00:28

回答

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

我想你想的最後TextBlockx:Name="stat2",而不是TextBox之前。

當您更改LastName時,將調用PropertyChanged事件處理程序,該處理程序將更改文本值stat2。由於stat2TextBox,它的值通過TwoWay綁定綁定到LastName,這會導致綁定機制將您設置的值發送回視圖模型。這導致另一個PropertyChanged事件觸發,這將更改值stat2,這會導致另一個PropertyChanged事件觸發....此無限循環不會停止,這就是您遇到堆棧溢出錯誤的原因。

你沒有得到與FirstName因爲stat1任何這樣的堆棧溢出是一個TextBlock在其Text財產沒有約束力。

+0

謝謝盧克。你是對的。標籤之間的跳躍使我忘記了名稱的添加位置。這是很大的幫助。 – 2012-07-28 17:57:59

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屬性:它將評估您觸發異常的原始propertychanged方法的條件。如果火災更改了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屬性值,並且TextBlocks被綁定爲獲取Check屬性的結果(如前所述),在Person類的其他屬性被更改後通知其更改。

<?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 2012-07-27 19:37:02

+0

只有當stat1.TextChanged將被一個改變Person的方法處理時,纔會發生這種情況。 OP做了那樣的事情嗎?你也知道一種不同的方式?我想有必要看看XAML代碼。 – 2012-07-27 19:43:19

+0

我已經發布了xaml和Person類。我試過**靜態**,但編譯器並不高興。 – 2012-07-27 21:03:07

相關問題