c# - 遍历子控件时避免无限循环

标签 c# .net winforms controls

我正在编写一个简单的扩展方法来对控件及其所有子控件执行操作,我想知道是否必须担心两次遇到同一个控件。

安全:

public static void Traverse(this Control control, Action<Control> action)
{
    Traverse(control, action, new HashSet<control>());
}

private static void Traverse(this Control control, Action<Control> action, HashSet<Control> handled)
{
    handled.Add(control);
    foreach (Control child in control.Controls)
        if (!handled.Contains(child))
            Traverse(child, action, handled);
    action.Invoke(control);
}

可能不安全:

public static void Traverse(this Control control, Action<Control> action)
{
    foreach (Control child in control.Controls)
        Traverse(child, action, handled);
    action.Invoke(control);
}

哈希集是否需要保证此代码的安全?它只需要对每个控件调用一次操作,并且不能进入无限循环。父子控件的结构是否使我不需要担心这个问题?

用法:

this.Traverse(o => o.SuspendLayout());

// Do lots of UI changes

this.Traverse(o => o.ResumeLayout());

(可能)全面的方法:

public static class ControlExtensions
{
    public static void Traverse(this Control control, Action<Control> action)
    {
        Traverse(control, action, TraversalMethod.DepthFirst);
    }

    public static void Traverse(this Control control, Action<Control> action, TraversalMethod method)
    {
        switch (method)
        {
            case TraversalMethod.DepthFirst:
                TraverseDepth(control, action);
                break;
            case TraversalMethod.BreadthFirst:
                TraverseBreadth(control, action);
                break;
            case TraversalMethod.ReversedDepthFirst:
                TraverseDepthReversed(control, action);
                break;
            case TraversalMethod.ReversedBreadthFirst:
                TraverseBreadthReversed(control, action);
                break;
        }
    }

    private static void TraverseDepth(Control control, Action<Control> action)
    {
        Stack<Control> controls = new Stack<Control>();
        Queue<Control> queue = new Queue<Control>();

        controls.Push(control);
        while (controls.Count != 0)
        {
            control = controls.Pop();
            foreach (Control child in control.Controls)
                controls.Push(child);
            queue.Enqueue(control);
        }
        while (queue.Count != 0)
            action.Invoke(queue.Dequeue());
    }

    private static void TraverseBreadth(Control control, Action<Control> action)
    {
        Queue<Control> controls = new Queue<Control>();
        Queue<Control> queue = new Queue<Control>();

        controls.Enqueue(control);
        while (controls.Count != 0)
        {
            control = controls.Dequeue();
            foreach (Control child in control.Controls)
                controls.Enqueue(child);
            queue.Enqueue(control);
        }
        while (queue.Count != 0)
            action.Invoke(queue.Dequeue());
    }

    private static void TraverseDepthReversed(Control control, Action<Control> action)
    {
        Stack<Control> controls = new Stack<Control>();
        Stack<Control> stack = new Stack<Control>();

        controls.Push(control);
        while (controls.Count != 0)
        {
            control = controls.Pop();
            foreach (Control child in control.Controls)
                controls.Push(child);
            stack.Push(control);
        }
        while (stack.Count != 0)
            action.Invoke(stack.Pop());
    }

    private static void TraverseBreadthReversed(Control control, Action<Control> action)
    {
        Queue<Control> controls = new Queue<Control>();
        Stack<Control> stack = new Stack<Control>();

        controls.Enqueue(control);
        while (controls.Count != 0)
        {
            control = controls.Dequeue();
            foreach (Control child in control.Controls)
                controls.Enqueue(child);
            stack.Push(control);
        }
        while (stack.Count != 0)
            action.Invoke(stack.Pop());
    }
}

最佳答案

每个 child 都有一个 parent ,因此无需担心。

关于c# - 遍历子控件时避免无限循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3215166/

相关文章:

c# - 日历编程: How can I place,创建并确定使用MVVM表示任务的项目?

c# - 使用第三方库(带反射)较旧 .NET 版本的 .NET 应用程序

c# - 如何实现 ClickOnce 更新策略以仅更新版本之间更改的文件?

c# - 如何检查用户控件是否在 C# 中的其他控件前面?

c# - 如何为 DotNetOpenAuth 编写 VB 或 C# GUI 客户端?

c# - 如何在 C# 中使用热键启动程序?

c# - 执行存储在字符串变量中的# 命令?

c# - ImageMagick .NET 圆形图像重叠问题

.net - 可以防止子 AppDomains 中未处理的异常使主进程崩溃吗?

c# - .NET 的自动更新程序和 wyBuild/wyUpdate 的替代品?