如何在窗体外部访问和设置控件属性?该问题涉及IT技术。

3

我是一名编程新手,目前正在开发一个C# Windows Forms应用程序。

问题如下: 我有一个带有不同对象和控件的表单,例如:选项卡页面、文本框、计时器等。 我还有一个用户控件表单,我将其加载到主表单的一个选项卡页面中。

我想在用户控件中编写代码,如何操作主表单元素的属性。

例如:当我在用户控件表单上单击按钮时,它会将主表单的timer.Enabled控件设置为true。

5个回答

4
可以实现这一点,但是让用户控制访问和操作表单并不是最好的方式——最好让用户控制引发事件,并让主机表单处理事件。(例如,在处理按钮点击时,表单可以启用/禁用定时器等)
这样,如果需要,在不同的表单中可以以不同的方式使用用户控件;而且更容易理解正在发生什么。
更新: 在您的用户控件中,您可以声明一个事件——在按钮点击中,您会引发该事件:
namespace WindowsFormsApplication1
{
    public partial class UserControl1 : UserControl
    {
        public event EventHandler OnButtonClicked;


        public UserControl1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            EventHandler handler = OnButtonClicked;

            // if something is listening for this event, let let them know it has occurred
            if (handler != null)
            {
                handler(this, new EventArgs());
            }

        }
    }
}

然后在你的表单中添加用户控件。你可以通过以下方式来连接事件:

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            userControl11.OnButtonClicked += userControl11_OnButtonClicked;
        }

        void userControl11_OnButtonClicked(object sender, EventArgs e)
        {
            MessageBox.Show("got here");
        }


        }
    }

谢谢您的回答NDJ,但是您能否再解释一下您的解决方案?并且,您能否告诉我更多关于我方法的缺点,因为我想从我的错误中学习。谢谢! - szabolcsmolnar
控件默认不是公共的原因是为了防止其他组件更改它们 - 例如,如果任何类都可以访问您的表单中的文本框并更改它们,那么跟踪错误等会变得困难 - 如果只有表单更改它们,则要容易得多。 使用事件是在Form应用程序中通信的标准方式。 我已经更新了我的答案,并提供了一个更具体的示例。 - NDJ
无论我怎么努力,我就是无法让它工作,你能用吗?我尝试复制你的代码,但在 UserControl1.OnButtonClicked += new... 处显示错误,提示需要非静态字段、方法的对象引用...所以我创建了一个新实例,但什么也没发生。我对此感到非常困惑。我觉得我在这方面缺乏逻辑。为什么我不能说:嘿,听着,我是 Usercontrol1,我想将 Form1.Timer1.Enabled 属性操纵为值=true?这对我来说似乎是个逻辑上的举动。 - szabolcsmolnar
是的,它适用于我 - 我将用户控件拖到表单上,并使用了上面的代码(用户控件只有一个带事件的按钮)。您在表单上已经有一个用户控件了吗? 我理解你的意思 - 它看起来很复杂,但这是正确的方法。唯一的其他真正选择是使控件(例如计时器)内部并将Form1的实例传递给用户控件(例如自定义方法或构造函数),该实例可以存储在本地,然后根据需要进行操作。 - NDJ
我已经更新了示例,使用更简单的版本 - 我创建了一个新的Windows应用程序,添加了一个新的用户控件,在其上放置了一个按钮,并双击该按钮以创建button1_click事件。然后我构建了解决方案,以便用户控件将显示在工具箱中,将其拖动到Form1上并放置其余的代码。希望这可以帮助您。如果您有问题,最好更新您的问题并附上一些代码。 - NDJ
哦,我真是个傻瓜!:D 谢谢您提醒我应该将用户控件添加到表单中。在代码中,我添加了很多用户控件,但就是忽略了添加这一个。好吧,这真的帮了我,解决了我的问题。非常感谢您抽出时间来帮助我,非常感谢! - szabolcsmolnar

1
你可以将 timer1.Modifiers 属性设置为 "internal" 并使用 Form1 的实例进行访问:
form1.timer1.Enabled = true;

你需要一个类 Form1 的实例,而不是类本身。例如:
// INVALID
Form1.timer1.Enabled = true;

// VALID
var form1 = Form1.ActiveForm;
form1.timer1.Enabled = true;

但这不是一种很干净的方法,你最好使用NDJ的答案中描述的事件。


感谢您抽出时间!它仍然显示错误代码:...不包含'timer1'的定义,也没有接受类型为...的第一个参数的扩展方法'timer1'。但我想我会坚持NDJ的答案并尝试弄清楚。但还是谢谢您的回答! - szabolcsmolnar
@szabolcsmolnar 您需要将“timer1”替换为您的计时器(或要访问的控件)的名称(根据您的问题,我看到它被称为“Timer1”(大写),因此form1.Timer1.Enabled = true应该可以工作。 - pascalhein
不,不是因为你的示例中有timer1,我才写了timer1。在我的代码中,我使用了正确的计时器名称,但它没有起作用。我尝试通过以下方式创建一个实例:Form1 form1 = new Form1(); 这样可以解决问题,但这不是可行的解决方案,因为我需要操作已经打开的窗体而不是另一个实例。 - szabolcsmolnar
@szabolcsmolnar,您正在创建另一个Form1实例。相反,如我所建议的,您可以使用Form1.ActiveForm或将对当前打开窗口的引用传递给UserControl的构造函数。 - pascalhein
我之前已经成功地使用过这种方法。请展示你实现代码的方式,以帮助你找到错误。 - pascalhein
显示剩余2条评论

1
你可能需要重新考虑一下你想要达成的目标。然而,为了回答你的问题,这是可以完成的。
最好的方法是在你的UserControl中创建一个名为MainForm的属性:
public Control MainForm {
    get;
    set;
}

然后,在你的主窗体的Load事件中,将该属性设置为它本身:
userControl1.MainForm = this;

最后,在您的用户控件中设置主窗体的计时器:
protected button_click(object sender, EventArgs e)
{
    timerName = "timer1";
    EnableTimer(timerName);
}

private void EnableTimer(timerName)
{
    var timer = MainForm.Controls.FirstOrDefault(z => z.Name.ToLower().Equals(timerName.ToLower());
    if (timer != null)
    {
         ((Timer)timer).Enabled = true;
    } else {
         // Timer was not found
    }
}

谢谢您的回答,icemanind。但是我得到了与csharpler的答案相同的错误。一旦我将代码写入主窗体,就会出现错误消息,指出需要非静态字段、方法或属性"Myprogram.UserControl1.MainForm.get"的对象引用。您知道为什么会发生这种情况吗? - szabolcsmolnar

1
这很简单。它被称为事件。在用户控件上,您将公开一个带有事件处理程序的事件,以供表单订阅。
public partial class MyUserControl : UserControl
{
    /// You can name the event anything you want.
    public event EventHandler ButtonSelected;

    /// This bubbles the button selected event up to the form.
    private void Button1_Clicked(object sender, EventArgs e)
    {
         if (this.ButtonSelected != null)
         {
              // You could pass your own custom arguments back to the form here.
              this.ButtonSelected(this, e)
         }
    }
}

现在我们已经有了用户控件代码,我们将在表单代码中实现它。可能在表单的构造函数中,您会有一些类似下面的代码。
MyUserControl ctrl = new MyUserControl();
ctrl.ButtonSelected += this.ButtonSelected_OnClick;

最后在表单代码中,您将有一个订阅事件的方法,如下面的代码所示,它将使计时器启用。

private void ButtonSelected_OnClick(object sender, EventArgs e)
{
    this.Timer1.Enabled = true;
}

这就是如何允许用户控件上的事件在表单上设置对象。

谢谢,它也正常工作了!我无法将其标记为已解决,但我真的很感谢您的时间! - szabolcsmolnar

0

你需要放置以下代码:

(`userControl11.OnButtonClicked += userControl11_OnButtonClicked;`) 

在Visual Studio中,有一个单独的文件。另一个文件名为'Form1.Designer.cs',可以在Solution Explorer面板下找到。

Form1 >> Form1.cs >> Form1.Designer.cs

希望这可以帮助你!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接