创建静态Windows.Forms.Control

时间:2015-03-31 12:28:48

标签: c# winforms

我有一个项目,我委托创建(静态)库的功能?我所有其他项目中使用的类。在这些情况下,它通过解决方案引用。

例如,我有一个扩展程序,可以在给定的GroupBox面板中创建复选框,并且效果很好:

public static void PreencheCheckboxesPanel(this Panel p, List<CheckBox> listaCheckBoxs) {
    var count = 0;
    listaCheckBoxs.ForEach(
        i => {
            i.Location = new Point(10, 10 + ((count) * 25)); //"dynamic" and not-so-effective resizing here
            i.AutoSize = true;
            count++;
        });
    p.Controls.AddRange(listaCheckBoxs.ToArray());
}}

问题是,我需要在列表顶部插入一个静态复选框,它会收到一个方法(un)?检查下面的所有复选框。 所以我的代码将成为

internal static CheckBox CKB_ancora = new CheckBox(){};
public static void PreencheCheckboxesPanel(this Panel p, List<CheckBox> listaCheckBoxs) {
    var count = 0;
    if (adicionaAncora) {
        CKB_ancora.Text = textoAncora;
        CKB_ancora.CheckedChanged += (sender, args) => {
            ChecaCheckBoxes(p, CKB_ancora.Checked);
        };
        listaCheckBoxs.Insert(0, CKB_ancora);
    }
    listaCheckBoxs.ForEach(
        i => {
            i.Location = new Point(10, 10 + ((count) * 25)); //"dynamic" and not-so-effective resizing here
            i.AutoSize = true;
            count++;
        });
    p.Controls.AddRange(listaCheckBoxs.ToArray());
}}

其中ChecaCheckBoxes是另一个

public static void ChecaCheckBoxes(this Panel b, bool checkStatus = true) {
    var listaCheckBoxs = (from Control c in b.Controls where c is CheckBox select (CheckBox)c).ToList();
    listaCheckBoxs.ForEach(
        i => {
            i.Checked = checkStatus;
        });
}

CKB_ancora需要是解决方案范围内识别的对象。

原因?我有另一个名为GetSelectedCheckBoxes的扩展名,它将用于返回组框中所有已检查的... ah ...复选框。并且,为了确保&#34;锚定#34; (我称之为,因为我没有(un)?check-all复选框的名称)也不会被退回。

如果我运行此代码,它将进行编译,但是......将在Application.SetCompatibleTextRenderingDefault上运行InvalidOperationException,就在Main();显然,在mainpoint上运行此方法之前无法创建/即时控件,这是&#34; static&#34; 的确切定义。

问题:知道我需要一种方法来保持这个特定的检查解决方案范围可见...我该怎么做?

1 个答案:

答案 0 :(得分:2)

不幸的是,你没有提供a good, minimal, complete code example,而且缺乏足够的背景,很难提供好的,具体的建议。

那就是说,似乎在你的这个静态类的某个地方,你有一个名为CKB_ancora的字段,你可能正在使用字段初始值设定项初始化它,可能是这样的:

private CheckBox CKB_ancora = new Checkbox();

完成此操作后,您发现当初始化类时(通常在第一次运行时访问类中的某些内容时),这种情况发生得太快而引发异常。

假设这是正确的,那么在我看来,最明显和最简单的&#34;修复&#34;是懒惰地初始化对象。例如:

private Lazy<CheckBox> _ckb_ancora =
    new Lazy<CheckBox>(() => new CheckBox());

private CheckBox CKB_ancora { get { return _ckb_ancora.Value; } }

这将把对象存储包装在一个属性中,该属性又使用Lazy<T>的实例来推迟初始化,直到第一次任何代码实际尝试访问它为止。


现在,那就是说,我不太喜欢你的方法,在一些实例化的对象中使用静态成员。如果使用您的库的人想要将代码用于两个或更多Panel个实例,该怎么办? Control(包括CheckBox)一次不能成为其他Control个以上的孩子,因此拥有Control的单个静态实例只是不会起作用。

恕我直言,最好使用一些识别功能,例如Name的{​​{1}}或Tag属性来适当地处理控件(例如将其过滤掉) (枚举)。

例如:

CheckBox

并且,例如:

public static void PreencheCheckboxesPanel(this Panel p, List<CheckBox> listaCheckBoxs) {
    var count = 0;
    if (adicionaAncora) {
        CheckBox CKB_ancora = new CheckBox();

        CKB_ancora.Text = textoAncora;
        CKB_ancora.Name = "CKB_ancora";
        CKB_ancora.CheckedChanged += (sender, args) => {
            ChecaCheckBoxes(p, CKB_ancora.Checked);
        };
        listaCheckBoxs.Insert(0, CKB_ancora);
    }
    listaCheckBoxs.ForEach(
        i => {
            i.Location = new Point(10, 10 + ((count) * 25)); //"dynamic" and not-so-effective resizing here
            i.AutoSize = true;
            count++;
        });
    p.Controls.AddRange(listaCheckBoxs.ToArray());
}}

这样,当你去检索public static void ChecaCheckBoxes(this Panel b, bool checkStatus = true) { var listaCheckBoxs = b.Controls .OfType<CheckBox>().Where(c => c.Name != "CKB_ancora").ToList(); listaCheckBoxs.ForEach( i => { i.Checked = checkStatus; }); } 控件列表时,会忽略你在开头添加的特殊控件。


即便如此,我认为代码仍然非常脆弱。上面会更好,但恕我直言,如果你不是首先使用静态成员,那么它可能会更好。即相反,您应该设计一些机制,允许您将辅助类的实例与它帮助的CheckBox对象相关联,这样您实际上可以初始化和存储每个-instance信息,不会遇到执行顺序问题,以及仅使用单个客户端的代码使用限制。

如果没有更好的代码示例,我也没有看到任何提供任何特定建议的好方法。