c# - winform教程 - wpf




在Windows窗体中访问另一个窗体上的控件的最佳方法? (12)

  1. 使用事件处理程序通知其他表单来处理它。
  2. 在子表单上创建一个公共属性,并从父表单访问它(使用有效的强制转换)。
  3. 在子窗体上创建另一个构造函数,用于设置窗体的初始化参数
  4. 创建自定义事件和/或使用(静态)类。

如果您使用非模态表单,最佳做法是#4。

首先,这是一个关于使用Windows窗体的桌面应用程序的问题,而不是ASP.NET问题。

我需要与其他表单上的控件进行交互。 我试图通过使用,例如,以下来访问控件...

otherForm.Controls["nameOfControl"].Visible = false;

它不像我期望的那样工作。 我最终得到了一个从Main抛出的异常。 但是,如果我将控件public而不是private ,那么我可以直接访问它们,因为......

otherForm.nameOfControl.Visible = false;

但这是最好的方法吗? 将控件public在另一种形式上被视为“最佳实践”吗? 是否有“更好”的方式来访问另一种形式的控件?

进一步说明:

这实际上是我提出的另一个问题的后续问题, 在C#中创建“树视图首选项对话框”类型界面的最佳方法? 。 我得到的答案非常好,解决了很多很多组织问题,我们在运行时和设计时都保持了UI的直接性和易用性。 然而,它确实提出了一个轻松控制界面其他方面的问题。

基本上,我有一个根表单,它实例化了根表单中面板中的许多其他表单。 因此,例如,其中一个子表单上的单选按钮可能需要更改主,根表单上的状态条图标的状态。 在这种情况下,我需要子表单与父(根)表单的状态条中的控件进行通信。 (我希望这是有道理的,而不是在“谁是第一个”的方式。)


@Lars,好好调用表格引用的传递,看到它也是我自己。 讨厌。 从未见过他们将它们传递给BLL层! 这甚至没有意义! 这可能会严重影响绩效吗? 如果BLL中的某个地方保留了引用,表单会保留在内存中吗?

你有同情心! ;)

@Ed,RE你关于制作Forms UserControls的评论。 Dylan已经指出根形式实例化了许多子表单,给人一种MDI应用程序的印象(我假设用户可能希望关闭各种表单)。 如果我在这个假设中是正确的,我认为他们最好保留为表格。 当然可以接受纠正:)


假设您有两个表单,并且您希望通过另一个表单隐藏一个表单的属性:

form1 ob = new form1();
ob.Show(this);
this.Enabled= false;

当你想通过form2按钮获得form1的焦点时,然后:

Form1 ob = new Form1();
ob.Visible = true;
this.Close();

在阅读了其他详细信息后,我同意robcthegeek :举办活动。 创建自定义EventArgs并通过它传递必要的参数。


将修饰符从公共更改为内部。 .Net故意使用私有修饰符而不是公共修饰符,因为防止对您的方法/属性/控件的任何非法访问。 事实上,公共修饰符可以随时随地访问,因此它们非常危险。 项目中的任何实体都可以访问您的方法/属性。 但是在内部修饰符中,没有正文(您当前的其他项目)可以访问您的方法/属性。

假设您正在创建一个具有一些秘密字段的项目。 因此,如果这些字段可以从您的项目中访问,那么它可能是危险的,并且与您最初的想法相反。 作为一个很好的推荐,我可以说总是使用内部修饰符而不是公共修饰符。

但有些奇怪!

我必须在VB.Net中告诉我们我们的方法/属性仍然是私有的,它可以通过调用form作为变量从其他表单/类访问,没有任何其他问题。

我不知道为什么这种编程语言的行为与C#不同。 我们知道两者都在使用相同的平台,他们声称它们几乎是相同的后端平台,但正如您所看到的,它们仍然表现不同。

但我用两种方法解决了这个问题。 无论; 通过使用接口(这不是推荐,如你所知,接口通常需要公共修饰符,并且不建议使用公共修饰符(正如我上面所说)),

要么

在静态类和静态变量的某个地方声明你的整个Form,并且仍然有内部修饰符。 然后,当您假设使用该表单向用户显示时,请将新的Form()构造传递给该静态类/变量。 现在它可以随心所欲地访问。 但是你还需要更多的东西。 您也可以在Designer File of Form中声明元素内部修饰符。 您的表格是开放的,它可以随处访问。 它可以很好地为你工作。

考虑这个例子。

假设您要访问Form的TextBox。

因此,第一项工作是在静态类中声明静态变量(静态的原因是在将来不使用任何新的keywork时易于访问)。

第二个去那个表格的设计师类,假设可以被其他表格访问。 将其TextBox修饰符声明从private更改为internal。 别担心; 更改后,.Net永远不会再将其更改为私有修改器。

第三,当你想调用那个窗体打开时,所以将新的Form构造传递给那个静态变量 - >> static class。

第四; 从任何其他表单(项目中的任何位置),您可以访问该表单/控件,而From是打开的。

看看下面的代码(我们有三个对象.1-一个静态类(在我们的例子中我们将它命名为A)

2 - 任何想要打开最终表格的形式(具有TextBox)(在我们的示例FormB中)。

3 - 我们需要打开的真实表单,我们假设访问其内部TextBox1(在我们的示例FormC中)。

看下面的代码:

内部静态类A {

internal static FormC FrmC;

}

FormB ... {。 。 。

A.FrmC = new FormC();

。 。 。

}

FormC(设计器文件)。 。 。 {

 internal System.Windows.Forms.TextBox TextBox1;

}

当FormC打开时,您可以随时随地访问该静态变量(此处为FormC)及其内部控件(此处为Textbox1)。

任何评论/想法让我知道。 我很高兴听到你或任何其他人关于这个话题的更多信息。 老实说,过去我对这个提到的问题有一些问题。 最好的方法是第二种解决方案,我希望它可以为你工作。 让我知道任何新的想法/建议。

谢谢,最诚挚的问候

Mansoor Bozorgmehr

[email protected]


您可以

  1. 在子表单上创建一个带有所需参数的公共方法,并从父表单调用它(使用有效的强制转换)
  2. 在子表单上创建一个公共属性并从父表单访问它(使用有效的强制转换)
  3. 在子窗体上创建另一个构造函数,用于设置窗体的初始化参数
  4. 创建自定义事件和/或使用(静态)类

如果您使用非模态表单,最佳做法是#4。


您的孩子表格真的需要成为表格吗? 它们可能是用户控件吗? 通过这种方式,他们可以轻松地为主窗体提升事件来处理,并且可以更好地将其逻辑封装到单个类中(至少在逻辑上,它们已经在所有类之后)。

@Lars:你就在这里。 这是我在开始的日子里所做的事情,并且从那时起就没有这样做了,这就是为什么我首先建议提出一个事件,但是我的另一种方法真的会破坏任何封装的外观。

@Rob:是的,听起来不错:)。 在这一个0/2 ...


我个人会建议要这样做......如果它正在响应某种行为并且需要改变它的外观,我宁愿提出一个事件并让它自行解决......

形式之间的这种耦合总是让我感到紧张。 我总是试图让UI尽可能轻松独立

我希望这有帮助。 也许你可以扩展这个场景,如果没有?


我同意为此使用事件。 由于我怀疑您正在构建MDI应用程序(因为您创建了许多子表单)并动态创建窗口并且可能不知道何时取消订阅事件,我建议您查看弱事件模式 。 唉,这仅适用于框架3.0和3.5,但类似的东西可以通过弱引用相当容易地实现。

但是,如果要根据表单的引用在表单中查找控件,仅仅查看表单的控件集合是不够的。 由于每个控件都有自己的控件集合,因此您必须通过它们全部递归来查找特定控件。 您可以使用这两种方法(可以改进)来实现。

public static Control FindControl(Form form, string name)
{
    foreach (Control control in form.Controls)
    {
        Control result = FindControl(form, control, name);

        if (result != null)
            return result;
    }

    return null;
}

private static Control FindControl(Form form, Control control, string name)
{
    if (control.Name == name) {
        return control;
    }

    foreach (Control subControl in control.Controls)
    {
        Control result = FindControl(form, subControl, name);

        if (result != null)
            return result;
    }

    return null;
}

步骤1:

string regno, exm, brd, cleg, strm, mrks, inyear;

protected void GridView1_RowEditing(object sender, GridViewEditEventArgs e)
{
    string url;
    regno = GridView1.Rows[e.NewEditIndex].Cells[1].Text;
    exm = GridView1.Rows[e.NewEditIndex].Cells[2].Text;
    brd = GridView1.Rows[e.NewEditIndex].Cells[3].Text;
    cleg = GridView1.Rows[e.NewEditIndex].Cells[4].Text;
    strm = GridView1.Rows[e.NewEditIndex].Cells[5].Text;
    mrks = GridView1.Rows[e.NewEditIndex].Cells[6].Text;
    inyear = GridView1.Rows[e.NewEditIndex].Cells[7].Text;

    url = "academicinfo.aspx?regno=" + regno + ", " + exm + ", " + brd + ", " +
          cleg + ", " + strm + ", " + mrks + ", " + inyear;
    Response.Redirect(url);
}

第2步:

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        string prm_string = Convert.ToString(Request.QueryString["regno"]);

        if (prm_string != null)
        {
            string[] words = prm_string.Split(',');
            txt_regno.Text = words[0];
            txt_board.Text = words[2];
            txt_college.Text = words[3];
        }
    }
}

这看起来像是将演示文稿与数据模型分离的主要候选者。 在这种情况下,您的首选项应存储在一个单独的类中,该类在特定属性发生更改时触发事件更新(如果您的属性是离散集,则查看INotifyPropertyChanged;如果它们是更自由格式的基于文本的键,则查看单个事件)。

在树状视图中,您将对首选项模型进行更改,然后它将触发事件。 在您的其他表单中,您将订阅您感兴趣的更改。在用于订阅属性更改的事件处理程序中,您使用this.InvokeRequired查看您是否在正确的线程上创建UI如果没有调用,则使用this.BeginInvoke调用所需的方法来更新表单。


public void Enable_Usercontrol1()
{
    UserControl1 usercontrol1 = new UserControl1();
    usercontrol1.Enabled = true;
} 
/*
    Put this Anywhere in your Form and Call it by Enable_Usercontrol1();
    Also, Make sure the Usercontrol1 Modifiers is Set to Protected Internal
*/




controls