C# 无法计算表达式,因为当前线程处于堆栈溢出状态

C# 无法计算表达式,因为当前线程处于堆栈溢出状态,c#,wpf,xaml,C#,Wpf,Xaml,正如我所学。。。我已经创建了一个简单的数据绑定项目,它可以很好地处理一段数据,例如firstName。但是,当我试图使用lastName编译器时,会抛出一个运行时错误,如 **无法计算表达式,因为当前线程处于堆栈溢出状态** 这是代码。如您所见,第二个字段(姓氏)被注释掉,因为它导致堆栈溢出。如有任何评论,我们将不胜感激 public partial class MainWindow : Window { Person p; public MainWindow() {

正如我所学。。。我已经创建了一个简单的数据绑定项目,它可以很好地处理一段数据,例如firstName。但是,当我试图使用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";
    }

}
编辑:

XAML:


每次更改属性时,您都会更改一个属性(文本值),该属性会触发另一个属性更改事件,该事件会更改文本属性,该属性会触发

你知道这是怎么回事吗

您需要在更改文本属性时禁用事件触发,或者不在属性已更改事件处理程序的上下文中更改它


由于我们没有您的
Person
类的详细信息,我们不知道它是否已经支持某种机制来禁用事件触发,或者在不触发事件的情况下更改值。如果不存在,您可能需要创建自己的。如何做到这一点将取决于该类的实现。

我认为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编程代码实践。我认为您应该主要使用绑定和DependenciesProperty编写代码

编辑

  • 正如其他人所说,您可能将stat1名称分配给了错误的对象,这启动了抛出StackOverflowException的无限递归
  • 在Person类中,必须使用属性名称而不是属性值调用PropertyChanged
  • 下面是一个工作示例,并没有因为这个问题而停止,我还想向您展示WPF平台如何允许您将所有主要的精化任务从视图类中提取出来,并允许您按照范例在模型类中移动该阶段

    在person类中增加了检查属性:它评估触发异常的原始propertychanged方法的条件。每次在类中,如果为CheckFirstName或CheckLastName的更改触发changed事件,则FirstName或LastName属性都会发生更改。通过这种方式,您不需要为此目的处理视图类中的更改事件,因为该模型类已经完成了条件的计算,并且结果对于绑定对象可用

    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对象的DependecProperty定义

    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();
        }
    }
    
    主窗口XAML:每个组件都以正确的方式绑定到Person DependencyProperty。文本框被绑定以更新Person属性值,文本块被绑定以获取检查属性的结果,该属性(如前所述)在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>
    

    我认为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
    时,将调用PropertyChanged事件处理程序,从而更改
    stat2
    的文本值。由于
    stat2
    TextBox
    ,其值通过
    two-way
    绑定绑定到
    LastName
    ,这会导致绑定机制将您设置的值发送回视图模型。这会引发另一个PropertyChanged事件,从而更改
    stat2
    的值,从而引发另一个PropertyChanged事件。。。。这种无休止的循环不会停止,这就是为什么会出现堆栈溢出错误


    使用
    FirstName
    不会出现任何此类堆栈溢出,因为
    stat1
    是一个
    TextBlock
    ,其
    Text
    属性上没有绑定。

    您可以发布您的
    Person
    类吗?编辑:另外,您的
    stat1
    stat2
    文本字段是否绑定到此人?还要发布WPF控件的XAML。使用绑定到正确上下文的XAML修复了所有这些…多亏了所有。我刚刚添加了Person类。stat1和stat2是TextBlocksXaml文件。进行此更改应该会产生相同的结果。您仍在更改property changed事件中的属性,从而导致无限递归。只有当stat1.TextChanged由更改Person的方法处理时,才会发生这种情况。OP做过这样的事吗?你也知道另一种方式吗?我想也需要查看XAML代码。我已经发布了XAML和Person类。我尝试了静态编译,但编译器对此不满意。谢谢Luke。你说得对。在标签之间跳跃使我忘记了在哪里添加名称。这帮了大忙。
    <?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>
    
        <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" />