C#中WinForms的动态变量名使用

5

我不确定怎样表达最好,但我想知道在C#(3.5)中是否可以进行动态变量名访问。

这是我目前正在寻求改进或用循环更加优雅的代码:

    private void frmFilter_Load(object sender, EventArgs e)
    {
        chkCategory1.Text = categories[0];
        chkCategory2.Text = categories[1];
        chkCategory3.Text = categories[2];
        chkCategory4.Text = categories[3];
        chkCategory5.Text = categories[4];
        chkCategory6.Text = categories[5];
        chkCategory7.Text = categories[6];
        chkCategory8.Text = categories[7];
        chkCategory9.Text = categories[8];
        chkCategory10.Text = categories[9];
        chkCategory11.Text = categories[10];
        chkCategory12.Text = categories[11];  


    }

有没有一种方式可以实现类似于("chkCategory" + i.ToString()).Text这样的操作?

我可能完全暴露了我对新的C#特性动态部分的无知,但我认为C#是一种编译语言。因此,要实现这一点,您必须创建编译器的实例,生成代码,然后在拥有控件的线程上下文中执行代码。这是不切实际的。 - Todd Richardson
回答中的一般问题:在使用WinForms设计器时,处理复选框数组的最佳方法是什么? - Awaken
这就是反射被发明的原因(在您的特殊情况下,您还可以通过它们的名称访问控件)。 - codymanix
@Awaken:您可以使用System.Windows.Forms.CheckedListBox控件,就像我在我的答案中所示。只需将该控件拖放到设计器上即可。如果您已经知道了项目,则可以使用 Items 属性进行设置。否则,可以在调用 InitializeComponents() 后的窗体构造函数中设置 DataSource 属性。 - Ani
7个回答

7

是的,你可以使用

  Control c = this.Controls.Find("chkCategory" + i.ToString(), true).Single();
  (c as textBox).Text = ...;

添加一些错误检查并将其封装在一个好的(扩展)方法中。


编辑:它返回Control[],因此需要在末尾添加[0].Single()。已添加。


不错!我从我在问题上留下的评论中得到了纠正。 - Todd Richardson
@faux trot,这是一个库特性,而不是语言特性。我们搜索的并不是标识符,而是名称属性。不过这两者是同步的。 - H H
谢谢。这是一种我不熟悉的技术,但我有几个情况可以用到它。 - Awaken

5
for(...)
{
     CheckBox c = this.Controls["chkCategory" + i.ToString()] as CheckBox ;

     c.Text = categories[i];  
}

完美。像魔法一样运作。 - Awaken

2

您可以使用反射来完成这个任务。但是不建议这样做。

更好的方式是动态实例化一个控件列表,将它们以编程方式添加到您的表单中,并进行索引。


1
有时候将控件放入数组或集合中可能会有所帮助,例如:
Checkbox[] chkCataegories = new Checkbox[] { chkCategory1, chkCategory2 ... };
for(int i = 0; i < chkCategories.Length; i++)
    chkCategories[i].Text = categories[i];

作为另一种方法,您可以在运行时动态创建复选框而不是设计时:
for(int i = 0; i < categories.Length; i++)
{
    Checkbox chkCategory = new chkCategory { Text = categories[i] };
    someContainer.Controls.Add(chkCategory);
}

至少对于动态创建的控件,当你添加新类别时,你不需要修改你的 GUI 或表单代码。

有没有一种好的方法可以在VS中使用WinForms设计器完成这个任务?还是说我必须放弃设计器,在Load事件中使用代码动态构建窗体? - Awaken

0

你不需要动态的方式来实现这个。将chkCategory1 - 12放入一个数组中,并使用for循环进行遍历。我建议你将其保存在一个字段中,并在表单构建时进行初始化,因为chkCategory似乎与之相关。但是如果你想要一个简单的示例来演示如何在这种简单的方法中实现它,那么可以像这样:

private void frmFilter_Load(object sender, EventArgs e)
{
    var chkCategories = new [] { chkCategory1, chkCategory2, chkCategory3, .......... };
    for(int i = 0 ; i < chkCategories.Length ; i++ ) 
        chkCategoies[i].Text = categories[i];
}

你对应用程序更了解,因此你可以避免编写所有控件名称 - 例如,如果它们放置在共同的父控件上,则可以通过遍历其子级来找到它们。


我觉得楼主不是指dynamic这个动态的意思。 - H H
这个在WinForms设计器中如何工作?我需要手动在代码中定义所有的位置和属性吗? - Awaken

0

不,但你可以做类似这样的事情(未经测试,请注意语法错误):

private readonly CheckBox[] allMyCheckboxes = new CheckBox[] { chkCategory1, chkCategory2, ... }

然后你只需要做

for (i = 0; i < 12; i++) allMyCheckboxes[i].Text = categories[i];

0

"this.Controls["chkCategory" + i.ToString()]"和"this.Controls.Find("chkCategory" + i.ToString(), true)"都不起作用...前者告诉您[]的内容不是int,后者告诉您ControlCollection中没有Find的定义。

使用 "Control myControl1 = FindControl("TextBox2");"代替。

我需要这个表单,因为我正在循环另一个数组,提取值并使用它们来填充表单字段。查找label1、label2、label3等要容易得多。


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