【问题标题】:Unable to display programmatically set Winforms textbox value无法以编程方式显示设置的 Winforms 文本框值
【发布时间】:2013-01-02 14:26:43
【问题描述】:

解决方案

我现在对此很自责,但是您会在下面的代码中注意到,我正在为 Form4 使用参数化构造函数。 C# 中参数化构造函数的标准过程是在声明之后使用:this()(我认为,至少对于 Forms)。这首先调用未参数化/默认构造函数,其中包含InitializeComponent(),它设置表单及其控件。

如果您使用了:this()

InitializeComponent() 绝对应该在参数化构造函数中,因为它使用“新”控件重新初始化您的表单。这会导致您的表单和控件处于模棱两可的状态,以及我得到的奇怪行为。

原始问题

我有一个表单,我希望控件(包括文本框)在第一个视图中具有初始值。这些值来自表单构建期间的一条 SQL 语句,因此我无法使用表单设计器。这个表单的元素/控件也是从一个几乎相同的表单复制粘贴的,因为那个是“添加”,而这个是“编辑”

问题是这样的:使用调试器显示我成功地从 SQL 中获取了良好的数据,并且设置 textbox.Text 成功,但是当显示表单时,它并没有反映所做的更改。这里的答案:https://stackoverflow.com/a/7830769/1655707 意味着可以简单地设置该值(大概在初始化或加载期间)。

我尝试在初始化期间、在 Load 事件和 Shown 事件中执行此操作,但这些都不起作用。调用Refresh()Application.DoEvents() 也没有任何作用。有什么我想念的吗?某些阻止此文本框正确更新/显示的事件?复制粘贴控件是否有意外的副作用?

我尝试以这种方式设置的所有控件都不会显示更改后的值,但文本框是最简单的,因为它没有索引可以弄乱。

    public Form4(int collIDFromParent, string collNameFromParent): this()
    {
        InitializeComponent();

        retCollID = collIDFromParent;
        retCollName = collNameFromParent;

        //Initialize these here so they activate on first use0
        button1.DialogResult = DialogResult.None;
        button2.DialogResult = DialogResult.Cancel;

        //PopulateEditData goes first for potential SQL failure
        PopulateEditData();

        textBox6.Text = "TEST";
    }

    private void Form4_Load_1(object sender, EventArgs e)
    {
        textBox1.Text = "TEST";
    }

    private void Form4_Shown_1(object sender, EventArgs e)
    {
        textBox2.Text = "TEST";
    }

是的,它们设置了不同的文本框,但它们都不起作用,所以差别不大。

典型的文本框更改处理程序。有人可能会认为它当前的编写方式可能会引发某种重置,但注释掉一行并不会改变我所关心的行为。

    private void textBox6_TextChanged_2(object sender, EventArgs e)
    {
            retCollName = textBox6.Text;
    }

【问题讨论】:

  • 当您复制/粘贴控件时,您是使用设计器还是通过代码进行的?
  • @Coding Designer,不用手动指定位置,保留布局
  • 您是否查看了设计器代码(通常隐藏在一个区域内)以确保它更新了所有内容以引用您粘贴的表单 to 并且没有仍然引用您粘贴的表格 来自
  • 事件处理程序真的被调用了吗?我看不到您在哪里连接事件处理程序(但可能在 InitializeComponent().
  • 您可以使用从数据库中检索项目所需的任何选项在表单的构造函数上设置覆盖,而不是拥有多个表单。对 Add 版本使用默认构造函数,对 Edit 使用重载。或者,您可以从正在检索的数据中创建一个对象,并在创建表单之前加载该对象(Add 的“默认”对象),然后将其传递给单个构造函数。

标签: c# winforms textbox controls


【解决方案1】:

我做了一个快速项目来测试这个功能。所有这三个选项都成功设置了 TextBox 的值。您在此处遇到的问题未在发布的代码中显示。之后有什么东西改变了 TextBox 的值,或者你引用了错误的 TextBoxes。我刚刚完成了与我们的应用程序类似的问题的调试。结果发现我们不知何故有两组重叠的文本框(我们实际使用的文本框位于一组空的文本框下面)。

    public Form1()
    {
        InitializeComponent();

        textBox1.Text = "TEST";
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        textBox2.Text = "TEST";
    }

    private void Form1_Shown(object sender, EventArgs e)
    {
        textBox3.Text = "TEST";
    }

【讨论】:

  • 不幸的是,这不是这里的问题,只有一组控件,将它们从位置显示中拉出来。我知道还有其他东西在改变它们,但这些是显示表单之前的最终事件,对吧?之后是否有我无法控制的事件?
  • 显示的确实是最终事件。这些 TextBox 上是否有任何可能更改文本的 TextChanged 事件处理程序?您是否使用了可能会更改文本的任何类型的数据绑定?
  • 每个都有 TextChanged 处理程序,但它们是简单的分配,就像编辑到问题中的示例一样。不,没有发生数据绑定(这是一位同事提出的潜在问题)。
【解决方案2】:

这可能是一个比这个问题所需的更简单的答案,但请确保您实际上是在调用Controls.Add(textBox1)。我注意到到目前为止没有人提到这一点。先签入 Designer 生成的代码。

如果您要动态添加控件,则必须自己调用它。

【讨论】:

  • 我又在设计器里看了一遍,确实添加了所有这些文本框。
【解决方案3】:

随着功能之间的简单更改(例如添加与编辑),表单的核心功能不会改变。您尝试处理的两个函数之间的唯一核心区别是一个新对象和一个现有对象。正因为如此,一个表单会比两个单独的表单要好得多。也省了很多工作,是OOP的核心之一。

我建议的另一件事是在创建表单之前检索数据。创建一个数据对象,其中包含您从数据库中检索的所有属性。为该数据类提供一个 Load 方法,该方法接受您要查找的记录的任何标识符。现在,您可以更轻松地进行设置了。

为了示例,我将在这里制作一些默认按钮,您的体验可能会有所不同。 :)

AddButton_Click(//default button click parameters) {
    Widget widget = new Widget();
    OpenWidgetForm(widget);
}

EditButton_Click(//default button click parameters) {
    Widget widget = new Widget();
    // You'll use the way you have now to determine which record to load,
    // and turn it to the id variable
    widget.Load(id);
    OpenWidgetForm(widget);
}

OpenWidgetForm(Widget widget) {
    frmWidget frm = new frmWidget(widget);
    frm.Show();
}

该代码将采用任何可将您带到添加/编辑表单的形式。

现在在您的添加/编辑表单中,您可以像这样更改它:

private Widget _widget;

public frmWidget() {
    Widget widget = new Widget();
    _widget = widget;
    LoadWidget();
}

public frmWidget(Widget widget) {
    _widget = widget;
    LoadWidget();
}

public void LoadWidget() {
    // go through each of the properties of your object
    // and set the values to the Text properties of each Textbox.
    txtName.Text = _widget.Name;
}

这样你就可以开始了。如果您有任何问题,请告诉我。

【讨论】:

  • 我越来越想,当我复制粘贴控件时产生了一些坏血;感谢您的建议和示例!忙于推进项目,忘记了 OOP 的宗旨!
  • 是的,要直接回答您的原始问题,很可能在某处失去参考的事件之间存在一些联系。甚至可能在部分类的另一半中,所有深层代码都是你永远不想接触的。仅仅复制这样的表格很少能达到您想要的效果。
  • 为了传播信息,我解决了这个问题。它在参数化构造函数中再次调用InitializeComponents()。它可能仍然与复制的控件有关,但在这种情况下,它似乎主要是用户错误。感谢您让我在赛道上看到它!
猜你喜欢
  • 1970-01-01
  • 2018-11-25
  • 1970-01-01
  • 1970-01-01
  • 2017-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多