2

私はかなり新しいのでC#、LINQを使用した良い解決策があると確信している少しの問題があります。

背景: CrystalReportsを使用する、継承したプロジェクトがあります。レポート自体には、すべて統一された方法で関連付けられたビューアフォーム[コンポーネント/コントロールを含む]があります(これらはマシンで生成されたものであると確信しています)。ReportClassデータベースプロパティを含む子孫のコンポーネント。データベースプロパティは、これらすべてのクラスに表示されるメソッド()を区別する唯一のものです。Log_On_Database私がやりたいのは、フォームを検索し、ReportClassそれを使用してローカルデータベース変数にプロパティの値を入力する共通の基本クラスを作成Log_On_Databaseして、単一の場所に実装できるようにすることです。

質問: LINQを使用しcomponentsて、フォームに属するすべての([コントロールだけでなく])を取得し、コントロールである(したがって独自のコントロールを持つことができる)ものを再帰的に取得するにはどうすればよいですか?

注:結果をaで取得するの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

すべてを 1 つの 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 に答える