如何按文本查找以编程方式创建的按钮?

时间:2014-10-08 21:10:10

标签: c# winforms c#-4.0

所以我的程序生成了一堆按钮,如下所示:

foreach (var subdir in dir.GetDirectories()) { 
    var path = subdir.Name;

    var button = new Button {
        Text = getFlavor(path) + "\t(" + path + ")",
        Width = Width,
        Height = 35,
        Top = y
    };

    button.Click += buttonClick;
    Controls.Add(button);

    if (button.Text.Contains("Kittens") 
        i++;
}

我想尝试这样的事情

if (i == 1) {
      [Button.ThatContains("Kitten)].Click;
}

“ThatContains”不是一个真正的方法。如何获取我以编程方式创建的按钮的引用?

5 个答案:

答案 0 :(得分:4)

您可以使用OfType<Button>查找容器控件中已添加它们的所有按钮(例如,Panel)。然后一个liitle位LINQ电源为您提供正确的按钮:

var kittenButtons = panel.Controls.OfType<Button>()
    .Where(btn => btn.Text.Contains("Kittens"));
foreach(Button btn in kittenButtons)
    btn.PerformClick();

如果您只想点击第一个:

Button kittenButton = panel.Controls.OfType<Button>()
    .FirstOrDefault(btn => btn.Text.Contains("Kittens"));
if(kittenButton != null)
    kittenButton.PerformClick();

对于它的价值,这里也是一个扩展方法,它通过延迟执行递归返回控件,允许仅使用第一个找到的Buttton或消耗所有的东西:

public static IEnumerable<T> GetChildControlsRecursive<T>(this Control root) where T : Control
{
    if (root == null) throw new ArgumentNullException("root");
    var stack = new Stack<Control>();
    stack.Push(root);
    while (stack.Count > 0)
    {
        Control parent = stack.Pop();
        foreach (Control child in parent.Controls)
        {
            if (child is T)
                yield return (T)child;
            stack.Push(child);
        }
    }
    yield break;
}

现在您可以使用与上面类似的代码来获取第一个匹配按钮或全部:

var kittenButtons = this.GetChildControlsRecursive<Button>()
    .Where(b => b.Text.Contains("Kittens"));
// search just until the first button is found
Button firstKittenButton = kittenButtons.FirstOrDefault();
if(firstKittenButton != null) firstKittenButton.PerformClick;
// loop all
foreach(Button btn in kittenButtons)
    btn.PerformClick();

答案 1 :(得分:2)

创建Button的子类以存储您想要的信息并改为实例化或使用Tag property

public class MyButton : Button
{
    public int ButtonID { get; set; }
}

public class MyApplication
{
    public void DoSomething()
    {
        int i; // todo: loop stuff
        var button = new MyButton
        {
            Text = getFlavor(path) + "\t(" + path + ")",
            Width = Width,
            Height = 35,
            Top = y,
            ButtonID = i
        };

    }
}

或者为什么不将按钮点击事件的sender参数转换为Button并检查文本?

public class MyApplication
{
    public void DoSomething()
    {
        var b = new Button();
        b.Click += b_Click;
    }

    public void b_Click(object sender, EventArgs e)
    {
        Button b = (Button)sender;
        switch (b.Text) {
            case "Kittens":
                return;
            default:
                return;
        }
    }
}

答案 2 :(得分:1)

像这样的东西

var button = FirstOrDefault(y => y is Button && y.Text.Contains("Kittens"));

if(button != null) button.PerformClick();

答案 3 :(得分:0)

为了获得引用,您可能需要使用任何其他类型的引用来做什么 - 将它们存储在某处,这在这里似乎并非如此。通常,您可以通过将按钮附加到Form来注册用户进行交互的按钮。假设您没有通过示例代码的外观执行此操作,我建议将它们存储到Dictionary<string, Button>中。

答案 4 :(得分:0)

您可以使用字典,也可以使用简单的递归循环(如果您将按钮固定在不同的容器中)。

private bool ClickButton(string buttonName, Control control) {
        if (control is Button && control.Text.Contains(buttonName) {
            ((Button)control)PerformClick();
            return true;
        } 

        if (control.HasChildren) {
            foreach (Control childControl in control.Controls) {
                if (ClickButton(buttonName, childControl)) {
                    return true;
                }

            }
        }
        return false;
    }

用法:ClickButton("Kittens", this);

或者您可以像某些人所建议的那样使用字典。

private Dictionary<string, Button> DynamicButtons = new Dictionary<string, Button>();

private void ClickDictionaryButton(string buttonName) {
        var matches = DynamicButtons.Where(x => x.Key.Contains(buttonName));
        foreach (var match in matches) {
            match.Value.PerformClick();
        }
}

用法:ClickDictionaryButton("Kittens", this);