具有通用和多个参数的方法

Method with generic and multiple parameters

我想 enable/disable 根据用户权限在 Windows Forms 应用程序中进行控制。

最初我想在每种形式 class 中编写一个方法来检查用户凭据,然后 enable/disable 它的控件。但后来我意识到我可以(也许)创建一个静态 class 方法,它将表单作为参数并完成工作。

所以我开始编写它,假设有时我只想启用一个或两个面板的控件,而不是整个表单。所以,我需要的参数是:

我在这项任务中遇到的困难是我在尝试使面板参数变化时遇到错误,而且我不知道如何设置可以采用任何形式的参数 class。我所有的表单 classes 显然都继承自通用表单 class,但我不知道如何应用它。

这是我得到的:

public static void Enable(TableLayoutPanel[] containers = null)
    {
        if (MyOF.isEnabled)
        {
            return;
        }
        else
        {
            try
            {
                foreach (TableLayoutPanel table in containers)
                {
                    foreach (Control control in table.Controls)
                    {
                        control.Enabled = false;
                    }
                }
            }
            catch (NullReferenceException)
            {
            }
        }
    }

如果我们记得 Form class 派生自 Control(间接地,通过派生自 ContainerControl,派生自 ScrollableControl,派生自Control), 而Enabled 属性 属于Control class, 我们可以写一个方法来启用any 控件的子控件(包括 FormTableLayoutPanel 控件),因为 Controls 集合也属于 Control class:

public static void EnableChildren(Control control, bool enabled = true)
{
    foreach (Control child in control.Controls)
    {
        child.Enabled = enabled;
    }
}

然后,如果我们还希望能够将其与控件集合一起使用(如您的示例所示),我们可以编写一个接受集合的重载:

public static void EnableChildren(IEnumerable<Control> controls = null, 
    bool enabled = true)
{
    if (controls == null) return;

    foreach (var control in controls)
    {
        EnableChildren(control, enabled);
    }
}

现在我们可以将其与 FormTableLayoutPanel 控件的集合(或任何在其 Controls 集合中包含控件的控件)一起使用。

使用示例:

var myForm = new Form1();

EnableChildren(this);     // 'this' is the current form
EnableChildren(myForm);   // a separate instance of a form control
EnableChildren(tableLayoutPanel1, false);  // A single TableLayoutPanel control

var tableLayoutPanels = new [] {tableLayoutPanel1, tableLayoutPanel2, tableLayoutPanel3};
EnableChildren(tableLayoutPanels);  // An array of tableLayoutPanel controls

我可以考虑您正在尝试做的事情的一种简单方法是这个。让我离开这里一会儿。我从事的项目中,所有表单控件都是从元数据构建的。 meta 附带了许可信息。因此,当控件被放置在它应该放置的位置时,它也会被禁用或根据元数据设置 read-only,但如果许可信息限制对它的访问,整个功能将被隐藏。回到你的方法,这不是一个坏方法,我看到这是可以做到的。它可以通过两种方式完成,(从我的脑海中快速想到)。

  1. 使用用户控件作为您想要的组件的表面enable/disable。创建接口
public interface IDisableableControl // make your fine name, no methods needed - marker interface
 . .  . . . 
public class MyFineUserControl : UserControl, IDisableableControl 

然后在您要编写的 static 方法中传递表单,并找到实现此接口的所有控件并按您希望的方式工作。

2。 同样,您可以使用每个控件上可用的 属性 Tag。这样,您实际上可以设置可以来自 DB-stored 元数据的复杂安全性 object,然后评估存储在 Tag 中的这个 object 以应用您的配置

你的方法需要递归

internal static void SetAllControls(Control parent)
{
    // Do something with control, for example parent.Enabled = false
    if (parent is IDisableableControl)
    {
       // here you use your logic, evaluate your parent you're dialing with and
       // enable/disable correspondingly 
       parent.Enabled = false;
       return;
    }
    foreach(var c in parent.Controls)
        SetAllControls(c);
} 

在现实生活中,您的 TOP parent 将是一种形式,不需要被禁用,但肯定 children 会。事实上,大多数时候,一旦你发现一个 UserControl 实现了 IDisableableControl 应该是行尾,这意味着你不需要进入 children 控件,因为它们都是坐在这个 parent 上,所有都将被禁用

我设法用下面的代码完成了我想做的事情,这几乎是我得到的所有有用答案的混合:

public static void EnableContainer(params Control[] containers)
    {
        if(containers.Count() == 0) { return; }
        if (MyOF.isEnabled)
        {
            return;
        }
        else
        {
            try
            {
                foreach (var container in containers)
                {
                    foreach (Control control in container.Controls)
                    {
                        control.Enabled = false;
                    }
                }
            }
            catch (NullReferenceException)
            {
            }
        }
    }
    public static void EnableForm<form>(form f) where form : Form
    {
        if (MyOF.isEnabled)
        {
            return;
        }
        else
        {
            foreach(Control control in f.Controls)
            {
                control.Enabled = false;
            }
        }
    }

欢迎社区提出改进建议,因为我远不是专业程序员。再次感谢大家。