2

我还很陌生C#,遇到了一些问题,我确信使用 LINQ 有一个很好的解决方案。

背景: 我继承了一个使用 CrystalReports 的项目,报告本身都有以统一方式关联的查看器表单 [包含组件/控件](我很确定它们是机器生成的),其中之一是一个ReportClass包含数据库属性的组件。数据库属性是唯一Log_On_Database区分所有这些类中出现的方法 ( ) 的东西。我想做的是创建一个公共基类,它搜索表单ReportClass并使用它来填充其本地数据库变量w/属性值,以便我可以Log_On_Database在单个位置实现。

问题: 如何使用 LINQ 来获取components属于表单的所有(不仅仅是[只是]控件)并递归地获取那些控件的(因此可以拥有自己的)?

注意:得到结果List会很棒,因为我可以测试长度为 0(出现严重错误)、1(预期)或更多(然后我可以在那些奇怪的情况下做我需要做的事情) -- 即使这都是生成的代码,我也不相信它没有以极其痛苦的方式进行修改。

4

2 回答 2

1

到目前为止,我有这个

    // Get all controls of a certain type:
    // http://stackoverflow.com/questions/3419159/how-to-get-all-child-controls-of-a-winform-of-a-specific-type-button-textbox
    public IEnumerable<Control> GetAll(Control control, Type type)
    {
        var controls = control.Controls.Cast<Control>();

        return controls.SelectMany(ctrl => GetAll(ctrl, type))
                                  .Concat(controls)
                                  .Where(c => c.GetType() == type);
    }

    protected ComponentCollection get_components(Component c)
    {
        Type parent = c.GetType();
        FieldInfo fieldInfo = parent.GetField("components", BindingFlags.Instance | BindingFlags.NonPublic);
        IContainer fieldData = (IContainer)fieldInfo.GetValue(components);

        return fieldData.Components;
    }

    protected void Log_On_Database()
    {
        // ReportClass decends from ReportDocument, which has the Database property we're interested in
        // this method grabs up any ReportDocument and decended objects. There should be only one.
        List<ReportDocument> reports = new List<ReportDocument>();

        // The list 'ctrls' contains all the Controls of 'this' form.
        List<Control> ctrls = GetAll(this, typeof(Control)).ToList();

        // Now we add all the components from all the controls which are ReportDocuments to the "reports" list.
        foreach (Control c in ctrls)
            foreach( Component x in get_components(c) )
            {
                if (x is ReportDocument)
                    reports.Add((ReportDocument)x);
            }

        switch (reports.Count)
        {
            case 0:
                MessageBox.Show("No report document found.");
                break;
            case 1:
                Log_On_Database( ((ReportDocument)reports[0]).Database );
                break;
            default:
                MessageBox.Show("Too many report documents found.");
                break;
        } // end switch

    } // end Log_On_Database

在一个 LINQ 语句中获得所有内容会很好。

于 2012-11-06T02:10:29.953 回答
0

使用 linq 你不能进行递归查询,所以GetAll应该保持原样。

但是你可以这样做:

var reports = GetAll(this, typeof(Control))
            .SelectMany(c => get_components(c))
            .OfType<ReportDocument>()
            .ToList();
于 2012-11-06T18:31:50.940 回答