C# 在Windows窗体中访问另一窗体上控件的最佳方法?

C# 在Windows窗体中访问另一窗体上控件的最佳方法?,c#,winforms,controls,C#,Winforms,Controls,首先,这是一个关于使用Windows窗体的桌面应用程序的问题,而不是一个问题 我需要与其他表单上的控件交互。我正在尝试通过使用以下控件来访问控件 otherForm.Controls["nameOfControl"].Visible = false; 它不像我期望的那样工作。我最终从Main抛出了一个异常。但是,如果我将控件设置为公共的,而不是私有的,那么我就可以直接访问它们,这样 otherForm.nameOfControl.Visible = false; 但这是最好的方法吗?将另一种

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

我需要与其他表单上的控件交互。我正在尝试通过使用以下控件来访问控件

otherForm.Controls["nameOfControl"].Visible = false;
它不像我期望的那样工作。我最终从
Main
抛出了一个异常。但是,如果我将控件设置为公共的,而不是私有的,那么我就可以直接访问它们,这样

otherForm.nameOfControl.Visible = false;
但这是最好的方法吗?将另一种形式的控件
公开
是否被视为“最佳实践”?是否有“更好”的方式访问其他表单上的控件

进一步解释:

这实际上是对我问的另一个问题的一种跟进。我得到的答案很好,解决了我在运行时和设计时在保持UI的直观性和易用性方面遇到的许多组织问题。然而,它确实提出了一个棘手的问题,即如何轻松控制接口的其他方面


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

我个人建议不要这样做。。。如果它对某种行为做出反应,并且需要改变它的外观,我更愿意提出一个事件,让它自己解决

形式之间的这种耦合总是让我紧张。我总是尽量保持UI的轻量级和独立性


我希望这有帮助。如果不是的话,也许您可以对场景进行扩展?

我会在父窗体中处理这个问题。您可以通过事件通知另一个窗体它需要修改自身。

您可以创建一个属性来控制其可见性,而不是将控件公开:

public bool ControlIsVisible
{
     get { return control.Visible; }
     set { control.Visible = value; }
}

这将为该控件创建一个适当的访问器,该访问器不会公开该控件的整个属性集。

第一个当然不起作用。窗体上的控件是私有的,仅在设计时对该窗体可见

把它全部公之于众也不是最好的办法

如果我想把某样东西暴露给外部世界(这也可能意味着另一种形式),我会把它作为公共财产

public Boolean nameOfControlVisible
{
    get { return this.nameOfControl.Visible; }
    set { this.nameOfControl.Visible = value; }
}
可以使用此公共属性隐藏或显示控件,或询问控件当前可见性属性:

otherForm.nameOfControlVisible = true;
您还可以公开完整控件,但我认为这太多了,您应该只从当前窗体外部显示您真正想要使用的属性

public ControlType nameOfControlP
{
    get { return this.nameOfControl; }
    set { this.nameOfControl = value; }
}

在阅读了附加细节后,我同意:发起一个活动。创建自定义EventArgs并通过它传递必要的参数。

您的子表单真的需要是表单吗?它们可能是用户控件吗?通过这种方式,它们可以很容易地引发事件供主窗体处理,并且您可以更好地将它们的逻辑封装到单个类中(至少在逻辑上,它们毕竟已经是类了)

@拉尔斯:你就在这里。这是我在刚开始的时候做的事情,从那以后我就没有做过,这就是为什么我第一次建议举办一次活动,但我的另一种方法确实会打破任何封装的假象


@罗布:是的,听起来不错:)。0/2关于这一点…

@Lars,关于传递表单引用的好消息,我自己也看到了。肮脏的但从没见过他们把它们传给BLL层!这根本没有道理!这可能会严重影响性能,对吗?如果在BLL中的某个地方保留了引用,那么表单将保留在内存中,对吗

我同情你!;)



@Ed,你对让表单成为UserControls有何评论。Dylan已经指出,根表单实例化了许多子表单,给人的印象是MDI应用程序(我假设用户可能希望关闭各种表单)。如果我在这个假设上是正确的,我认为它们最好以形式保存。当然可以更正:)

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

但是,如果希望根据窗体的引用在窗体中查找控件,仅查看窗体的控件集合是不够的。由于每个控件都有自己的控件集合,因此必须递归所有控件以找到特定的控件。您可以使用这两种方法(可以改进)


如果要创建更复杂的控件/模块/组件,则只能从另一个视图访问一个视图的内容。否则,您应该通过标准的模型-视图-控制器体系结构来实现这一点:您应该将所关心的控件的启用状态连接到某个提供正确信息的模型级谓词

例如,如果我只想在输入所有必需信息时启用Save按钮,我会有一个谓词方法,告诉表示该表单的模型对象何时处于可以保存的状态。然后在我选择是否启用按钮的上下文中,我只使用该方法的结果

这将导致业务逻辑与表示逻辑更清晰地分离,使两者都能更独立地发展—允许您创建一个前端和多个后端,或者创建多个前端和一个单独的应用程序
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;
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using LightInfocon.Data.LightBaseProvider;
using System.Configuration;

namespace SINJRectifier
{

    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }

        protected override void OnLoad(EventArgs e)
        {
            UserInterface userInterfaceObj = new UserInterface();
            this.chklbBasesList.Items.AddRange(userInterfaceObj.ExtentsList(this.chklbBasesList));
            MainFormInstance.MainFormInstanceSet = this; //Here I get the instance
        }

        private void btnBegin_Click(object sender, EventArgs e)
        {
            Maestro.ConductSymphony();
            ErrorHandling.SetExcecutionIsAllow();
        }
    }

    static class MainFormInstance  //Here I get the instance
    {
        private static MainForm mainFormInstance;

        public static MainForm MainFormInstanceSet { set { mainFormInstance = value; } }

        public static MainForm MainFormInstanceGet { get { return mainFormInstance; } }
    }
}
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);
}
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];
        }
    }
}
form1 ob = new form1();
ob.Show(this);
this.Enabled= false;
Form1 ob = new Form1();
ob.Visible = true;
this.Close();
internal static class A
{
    internal static FormC FrmC;
}

FormB ...
{
    '(...)
    A.FrmC = new FormC();
    '(...)
}

FormC (Designer File) . . . 
{
     internal System.Windows.Forms.TextBox TextBox1;
}
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
*/