【问题标题】:WPF/C# Numbers in TextBox Calculated Dynamically动态计算文本框中的 WPF/C# 数字
【发布时间】:2011-09-13 07:04:18
【问题描述】:

好的,所以我很确定我在这个小应用程序上走在正确的轨道上,但请告诉我。用户在 4 个可编辑的文本框中输入 4 个数字中的 3 个,然后自动计算缺失的数字。应用图片在这里:

http://www.peauproductions.com/images/lens_app.PNG

我研究过数据绑定,我认为我需要让值能够全局更改。我希望这些值能够动态更新/计算,而不必有计算按钮。

一旦我让它工作,我需要实施验证检查以确保只输入布尔值(无文本),并弹出一个工具提示说输入数字。

立即收到以下错误:

"'设置属性 'System.Windows.Controls.TextBox.Text' 抛出异常。'行号 '56' 和行位置 '51'。”

MainWindow.xaml 代码:

<Window x:Class="ConverterApp.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="ConverterApp" Height="360" Width="280"
    xmlns:c="clr-namespace:ConvertorApp;assembly=">

<Grid>
    <!--Outer Box + Title-->
    <TextBox Height="309" Width="248"
    Text=" Lens Calculator"
    IsReadOnly="True" 
    Margin="5,5,0,0"
    VerticalAlignment="Top"
    HorizontalAlignment="Left"
    BorderThickness="2.0"
    FontSize="16" FontFamily="Verdana" FontWeight="Bold">
        <TextBox.BorderBrush>
            <LinearGradientBrush StartPoint="0,0" EndPoint="1,1" >
                <GradientStop Color="Black" Offset="0" />
            </LinearGradientBrush>
        </TextBox.BorderBrush> 
    </TextBox>

    <!--Title Text-->
    <TextBox Height="50" Width="230"
    Text="Enter Image Width, Length and Either Distance or Lens Values Below"
    IsReadOnly="True" 
    Margin="14,29,0,0"
    TextWrapping="Wrap"
    VerticalAlignment="Top"
    HorizontalAlignment="Left"
    FontSize="12" FontFamily="Verdana"  FontStyle="Italic"
    BorderThickness="0">        
    </TextBox>

    <TextBox Height="20" Width="230"
    Text="Must Be Same Units (in,ft,cm,mm)"
    IsReadOnly="True" 
    Margin="14,59,0,0"
    VerticalAlignment="Top"
    HorizontalAlignment="Left"
    FontSize="10" FontFamily="Verdana" FontStyle="Italic"
    BorderThickness="0">
    </TextBox>

    <!--Distance-->
    <TextBox Height="20" Width="105"
    Text="Distance/Height:"
    IsReadOnly="True" 
    Margin="15,80,0,0"
    VerticalAlignment="Top"
    HorizontalAlignment="Left"
    FontFamily="Verdana"
    BorderThickness="0">
    </TextBox>

    <TextBox x:Name="DistanceBox" Height="20" Width="50"
    Text="{x:Static c:Variables.DistanceBox}"
    Margin="125,80,0,0"
    MaxLength="5" 
    VerticalAlignment="Top"
    HorizontalAlignment="Left"
    FontFamily="Verdana">
        <TextBox.BorderBrush>
            <LinearGradientBrush StartPoint="0,0" EndPoint="1,1" >
                <GradientStop Color="Black" Offset="0" />
            </LinearGradientBrush>
        </TextBox.BorderBrush>
    </TextBox>

    <!--Image Width-->
    <TextBox Height="20" Width="90"
    Text="Image Width:"
    IsReadOnly="True" 
    Margin="15,105,0,0"
    VerticalAlignment="Top"
    HorizontalAlignment="Left"
    FontFamily="Verdana"
    BorderThickness="0">
    </TextBox>

    <TextBox x:Name="WidthBox" Height="20" Width="50"
    Text="{x:Static c:Variables.WidthBox}"
    Margin="125,105,0,0"
    MaxLength="5" 
    VerticalAlignment="Top"
    HorizontalAlignment="Left"
             FontFamily="Verdana">
        <TextBox.BorderBrush>
            <LinearGradientBrush StartPoint="0,0" EndPoint="1,1" >
                <GradientStop Color="Black" Offset="0" />
            </LinearGradientBrush>
        </TextBox.BorderBrush>
    </TextBox>

    <!--Image Length-->
    <TextBox Width="95"
    Text="Image Length:"
    IsReadOnly="True" 
    Margin="15,130,0,161" HorizontalAlignment="Left"
    FontFamily="Verdana"
    BorderThickness="0">
    </TextBox>

    <TextBox x:Name="LengthBox" Height="20" Width="50"
    Text="{x:Static c:Variables.LengthBox}"
    Margin="125,130,0,0"
             MaxLength="5" 
    VerticalAlignment="Top"
    HorizontalAlignment="Left"
             FontFamily="Verdana">
        <TextBox.BorderBrush>
            <LinearGradientBrush StartPoint="0,0" EndPoint="1,1" >
                <GradientStop Color="Black" Offset="0" />
            </LinearGradientBrush>
        </TextBox.BorderBrush>
    </TextBox>

    <!--Lens Needed-->
    <TextBox Height="20" Width="90"
    Text="Lens (mm):"
    IsReadOnly="True" 
    Margin="15,155,0,0"
    VerticalAlignment="Top"
    HorizontalAlignment="Left"
    FontFamily="Verdana"
    BorderThickness="0">
    </TextBox>

    <TextBox x:Name="LensNeeded" Height="20" Width="50"
    Text="{x:Static c:Variables.LensNeeded}"
    Margin="125,155,0,0"
             MaxLength="4" 
    VerticalAlignment="Top"
    HorizontalAlignment="Left"
             FontFamily="Verdana">
        <TextBox.BorderBrush>
            <LinearGradientBrush StartPoint="0,0" EndPoint="1,1" >
                <GradientStop Color="Black" Offset="0" />
            </LinearGradientBrush>
        </TextBox.BorderBrush>
    </TextBox>

    <!--Info-->
    <TextBox Height="70" Width="230"
    Text="The lens focal length value represents the estimated mm value for a 1/4 inch sensor (Playstation Eye).  A lower mm will give a wider Field of View (FOV), and a higher value less FOV. "
    IsReadOnly="True" 
    TextWrapping="Wrap"
    Margin="15,180,0,0"
    FontSize="11"
    VerticalAlignment="Top"
    HorizontalAlignment="Left"
    FontFamily="Verdana"  FontStyle="Italic"
    BorderThickness="0">
    </TextBox>
    <TextBox Height="55" Width="230"
    Text="It is not recommend you use a lens of less than 2.5mm focal length with image tracking software due to distortion."
    IsReadOnly="True"
    FontSize="11"
    TextWrapping="Wrap"
    Margin="15,253,0,0"
    VerticalAlignment="Top"
    HorizontalAlignment="Left"
    FontFamily="Verdana"  FontStyle="Italic"
    BorderThickness="0">
    </TextBox>


</Grid>

MainWindow.xaml.cs 代码:

using System;
using System.Windows;

namespace ConvertorApp
{
    public class Variables
    {
        public const double DistanceBox = 0;
        public const double WidthBox = 0;
        public const double LengthBox = 0;
        public const double LensNeeded = 0;
        public const double WidthBased = 0;
        public const double LengthBased = 0;

        public void Calc()
        {
            double WidthBased = 2.952*(DistanceBox/WidthBox);
            double LengthBased = 3.984*(DistanceBox/LengthBox);

            if (WidthBased < LengthBased)
            {
                double LensNeeded = WidthBased;
            }else{
                double LensNeeded = LengthBased;
            }
        }
    }
}

如果您能想到一种更简单或更正确的方法来完成我正在尝试做的事情,请告诉我(我刚开始学习 WPF/C# 的东西)。谢谢


更新:

这是后面的代码,显示了下面的建议更改:

    using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;

namespace ConverterApp
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new Variables();
        }
    }

    public class Variables : INotifyPropertyChanged
    {
        // Declare the PropertyChanged event.
        public event PropertyChangedEventHandler PropertyChanged;

        private double m_distanceBox;
        public double DistanceBox
        {
            get { return m_distanceBox; }
            set
            {
                m_distanceBox = value;
                // modify calc to read the text values
                Calc();
                // Call NotifyPropertyChanged when the source property 
                // is updated.
                NotifyPropertyChanged("DistanceBox");
            }
        }

        private double m_widthBox;
        public double WidthBox
        {
            get { return m_widthBox; }
            set 
            {
                m_widthBox = value;
                // modify calc to read the text values
                Calc();
                // Call NotifyPropertyChanged when the source property 
                // is updated.
                NotifyPropertyChanged("WidthBox");
            }  
        }

        private double m_lengthBox;
        public double LengthBox
        {
            get { return m_lengthBox; }
            set
            {
                m_lengthBox = value;
                // modify calc to read the text values
                Calc();
                // Call NotifyPropertyChanged when the source property 
                // is updated.
                NotifyPropertyChanged("LengthBox");
            } 
        }

        private double m_lensBox;
        public double LensNeeded
        {
            get { return m_lensBox; }
            set
            {
                m_lensBox = value;
                // modify calc to read the text values
                Calc();
                // Call NotifyPropertyChanged when the source property 
                // is updated.
                NotifyPropertyChanged("LensNeeded");
            } 
        }

        public void Calc()
        {
            double WidthBased = 2.95 * (DistanceBox / WidthBox);
            double LengthBased = 3.98 * (DistanceBox / LengthBox);

            if (WidthBased < LengthBased)
            {
                LensNeeded = Math.Round(WidthBased,2);
            }else{
                LensNeeded = Math.Round(LengthBased,2);
            }
        }

        // NotifyPropertyChanged will raise the PropertyChanged event, 
        // passing the source property that is being updated.
        public void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this,
                    new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

**ERROR 我现在得到的是双重函数内 get {} 上的 StackOverflowException。有什么想法吗?

【问题讨论】:

  • 异常的InnerException是什么?
  • 您的 .cs 代码可能没有按照您的想法执行。 double LensNeeded = WidthBased; 行创建了一个名为 LensNeeded 的新变量,该变量在该行之后被丢弃,因为您不使用它。
  • @svick 请查看更新的代码隐藏。仍然不知道在哪里添加 DataContext。当我把它放在代码隐藏中时,错误不断出现。谢谢
  • 你一定是删除了MainWindow的C#代码。请参阅我的更新答案。
  • 这很可能是因为MainWindow 的 C# 代码和 XAML 代码的命名空间必须匹配。您在 XAML 中有 ConverterApp,但在 C# 中有 ConvertorApp

标签: c# wpf dynamic binding textbox


【解决方案1】:

抛出异常是因为该行

Text="{x:Static c:Variables.DistanceBox}"

实际上类似于

textBox.Text = Variables.DistanceBox;

这不会在 C# 中编译。在 XAML 中,它会引发异常。您应该做的是从您的字段中创建属性:

public double DistanceBox { get; set; }

并通过添加将Variables 设置为窗口的DataContext

DataContext = new Variables();

到窗口的构造函数(或Loaded 事件的处理程序)。

然后,您在 XAML 中使用绑定(它使用转换器将 strings 转换为 doubles):

Text="{Binding DistanceBox}"

要在值更改时调用Calc(),您可以将属性更改为

private double m_distanceBox;
public double DistanceBox
{
    get { return m_distanceBox; }
    set
    {
        m_distanceBox = value;
        Calc();
    }
}

为确保Variables 中的更改反映在文本框中,您应该实现INotifyPropertyChanged interface

编辑:MainWindow的C#代码:

public partial class MainWindow
{
    public MainWindw()
    {
        InitializeComponent();
        DataContext = new Variables();
    }
}

【讨论】:

  • 好的,所以我遵循了你所说的大部分内容。 DataContext = new Variables(); 在哪里走?我在想 my.xaml 顶部的 正确吗?你能展示一下它的外观吗?
  • 好的,所以如果我将更新后的代码放在命名空间中并在变量类的正上方,我会得到 InitializeComponent();不存在错误。
【解决方案2】:

您要设置文本吗?在 wpf 中,您需要使用设置直接文本属性的调用方法。

【讨论】:

    【解决方案3】:

    您在设置文本值时犯的错误:

    YourTextBox.Text=YourValue;
    

    在你的情况下:

    LensNeeded.Text = WidthBased.ToString();
    

    【讨论】:

      【解决方案4】:

      您应该为您的文本框使用数据绑定。

      1. 修改您的变量类以将 4 个值公开为字符串属性(您不能数据绑定到字段,只能绑定属性):

        public class Variables
        {
            // code as in your example
            public string LensValueNeeded 
            { 
              get { return LensNeeded.ToString(); }
              set { Calc(); }  // modify calc to read the text values
            }
        
            /// same for the other 3 values
        }
        

        确保修改 Calc 方法以从 TextBox 读取当前值,因为数据绑定设置为双向。您需要使用 double.Parse() 方法将字符串值转换回双精度值:

        double d = double.Parse(stringValue);

      2. 将 Grid 的 DataContext 设置为 Variables 类的实例

      3. 将 TextBox 的文本绑定到字符串属性:

        Text = {Binding LensNeededValue}
        

      【讨论】:

      • 如果我将 TextBox 中的值转换为变量类中的字符串,它表示我无法在 Calc() 中执行我的计算,因为它们现在是字符串。如何读取这些值以便进行计算?
      • 您需要读取字符串值并将它们转换为双精度值,例如 double d = double.Parse(stringValue)。我会把它添加到我的答案中。
      • 我很确定我已经修复了那部分。请参阅第一篇文章中的更新后代码。谢谢
      猜你喜欢
      • 2011-05-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多