4

左側の「Panel1」でユーザーが描画したリストボックス コントロールをホストする SplitContainer で構成される C# WinForms 'ListboxPanelControl' UserControl があります。SplitContainer の右側の「Panel2」は、項目がリストボックスに追加されると追加されるパネルをホストします。そのため、設計時のユーザーが最初の項目をリストボックスに追加すると、関連付けられたパネルが SplitContainer の「Panel2」に追加されます。リストボックスに 2 番目の項目が追加されると、2 番目のパネルが SplitContainer の「Panel2」に追加されます。次に、ユーザーがリストボックス項目を選択すると、関連するパネルが右側に表示されます。

この問題は、ユーザーがコントロール (ボタンなど) をツールボックスから現在アクティブな右側のパネル (現在選択されているリストボックス項目に対応するパネル) にドラッグ アンド ドロップしたときに発生します。プログラムで適切な Panel の Controls コレクションに追加しましたが、Microsoft Visual Studio IDE 内で「'子' はこの親の子コントロールではありません」というエラーが発生します。

私は問題を調査し、「別のコントロールの子であるコントロールが、デザイン時にコントロールをドロップすることを受け入れる方法」を示すいくつかの有用な記事を発見しました。例: http://www.codeproject.com/記事/37830/Designing-Nested-Controls

これは、「DesignerSerializationVisibility」属性を ControlDesigner の「EnableDesignMode」メソッドと組み合わせて使用​​し、VS IDE が別のコントロールへのコントロールのドロップを処理できるようにします。問題は、このシナリオでは、コントロールをホストしている UserControl のターゲットが効果的に修正され、事前に認識されていることです。私のコントロールでは、デザインタイムに他のコントロールをドロップできるターゲット ホスティング パネルは、事前にはわかりません。これは、私の UserControl 自体を「オンザフライ」で構築できるためです (ユーザーがさらにリストボックス項目を追加するため)。より潜在的なホスト パネルで)。

「DesignerSerializationVisibility」および「EnableDesignMode」メソッドをより柔軟な方法で使用しようとしましたが、前述の「子はこの親の子コントロールではありません」というエラーが発生するようです。

これがすべて理にかなっていることを願っています!? コードは現在、次のようになっています。

これは ListboxPanelControl クラス内にあります: ...

    [
    Category("Appearance"),
    DesignerSerializationVisibility(DesignerSerializationVisibility.Content)
    ]
    public Panel MainPanel
    {
        get
        {
            //Instead of returning a 'fixed' Panel we return whatever the currently
            //active Panel is according to the currently selected Listbox item
            if( mnCurrentlyActiveListBoxIndex >= 0 )
            {
                ListBoxEntry lEntry = (ListBoxEntry)listBox.Items[mnCurrentlyActiveListBoxIndex];
                return lEntry.RelatedPanel;
            }

            return null;
        }
    }

次に、ListBoxPanelControl の「OnControlAdded」イベントで、現在アクティブなパネルの「EnableDesignMode」を (単純な「SetDesignMode」ラッパーを介して) 呼び出し、コントロールを追加します。

protected override void OnControlAdded(ControlEventArgs e)
{
...
mDesigner.SetDesignMode(MainPanel, "MainPanel" + mnCurrentlyActiveListBoxIndex.ToString());
                    ListBoxEntry lEntry = (ListBoxEntry)listBox.Items[mnCurrentlyActiveListBoxIndex];
                    lEntry.RelatedPanel.Controls.Add(e.Control);
                    e.Control.BringToFront();
                    e.Control.Refresh();
...
}

問題を十分に明確に説明できたことを願っています。基本的に、WinForms UserControl に Control を追加できた人はいますか?ここで、Control をホストしているターゲット自体が子 Control であり、UserControl 自体が動的でオンザフライで構築されている場合は?

ヘルプ/洞察をありがとう!トニー。

4

1 に答える 1

2

将来の読者に役立つ場合に備えて、更新を提供すると思いました。「「子」はこの親の子コントロールではありません」というエラーを解決できました。問題は、「現在アクティブな」パネルで「EnableDesignMode」を呼び出して、コントロールをパネルにドロップできるようにしたことでしたが、「EnableDesignMode」メソッドの要件の 1 つが「子コントロールchild で指定された は、このコントロール デザイナーのコントロールの子です。」 ( http://msdn.microsoft.com/en-us/library/system.windows.forms.design.controldesigner.enabledesignmode.aspx )。また、現在アクティブなパネルは分割コンテナーの右側のパネルの子であり、「この」全体的な親 ListboxPanel コントロールではないため、

最終的に、コントロールもシリアル化する必要があることに気付き、多くの苦労と試行錯誤の末、結局「EnableDesignMode」を使用しなくなりました。代わりに、デザイナのサービスである IComponentChangeService、IDesignerHost、および ISelectionService を使用する方法が考えられました。("Controls.Add()" のように) 従来の方法でコントロールを追加するだけでなく、IDesignerHost の "CreateComponent" メソッドを使用して、デザイナーがそのすべてを「公式に」把握できるようにします。「元に戻す/やり直す」ことができるように、各操作をトランザクションにラップします。このようなビット:

DesignerTransaction designerTransaction = m_designHost.CreateTransaction("Add Page");
try
{
    Panel p = (Panel)m_designHost.CreateComponent(typeof(Panel));

    m_changeService.OnComponentChanging(mControl.MainPanel, TypeDescriptor.GetProperties(mControl.MainPanel)["Controls"]);

    ...
    ...
    //Add our Panel to our splitContainer Panel2's controls collection, etc

    ...
    m_changeService.OnComponentChanged(mControl.MainPanel, TypeDescriptor.GetProperties(mControl.MainPanel)["Controls"], null, null);

    //Use the selection service to select the newly added Panel
    m_selectionService.SetSelectedComponents(new object[] { p });

}
catch( Exception ex )
{
     designerTransaction.Cancel();
}
finally
{
     designerTransaction.Commit();
}

それが誰かに役立つことを願っています...

于 2012-10-04T14:21:17.003 に答える