2012-09-24 3 views
3

C# WinForms 'ListboxPanelControl'UserControl은 왼쪽의 'Panel1'에 사용자가 그린 Listbox 컨트롤을 호스팅하는 SplitContainer로 구성됩니다. SplitContainer의 오른쪽 'Panel2'는 항목이 목록 상자에 추가 될 때 추가되는 패널을 호스트합니다. 따라서 디자인 타임 사용자가 첫 번째 항목을 목록 상자에 추가하면 연결된 패널이 SplitContainer의 'Panel2'에 추가됩니다. 두 번째 항목이 목록 상자에 추가되면 두 번째 패널이 SplitContainer의 'Panel2'에 추가됩니다. 그런 다음 사용자가 목록 상자 항목을 선택하면 연결된 패널이 오른쪽에 표시됩니다.디자인 타임에 내 '온더 플라이'사용자 컨트롤에 컨트롤을 추가하는 중 ..?

문제는 디자인 타임에 사용자가 도구 상자의 컨트롤 (예 : Button)을 현재 활성화 된 오른쪽 패널 (현재 선택된 Listbox 항목에 해당하는 Panel)로 끌어다 놓을 때 발생합니다. 프로그래밍 방식으로 해당 Panel의 Controls 컬렉션에 추가하지만 "이 자식에 대한 자식 컨트롤이 아닙니다"오류이 Microsoft Visual Studio IDE 내에 있습니다. http://www.codeproject.com/Articles/37830/Designing-Nested-Controls

이를 :

나는, 예를 들어 문제를 연구하고 "어떻게 가진 컨트롤이 디자인 타임에 그것에 떨어 동의하는 또 다른 컨트롤의 자식 컨트롤을 할 수 있도록"보여주는 몇 가지 유용한 기사를 발견했습니다 "DesignerSerializationVisibility"특성을 ControlDesigner의 "EnableDesignMode"메서드와 함께 사용하여 VS IDE에서 다른 컨트롤에 컨트롤을 놓는 것을 처리 할 수 ​​있도록합니다. 문제는이 시나리오에서 UserControl의 대상 호스팅 컨트롤이 효율적으로 고정되어 있고 미리 알려진 사실입니다. 내 컨트롤을 사용하면 디자인 타임에 다른 컨트롤을 놓을 수있는 Panel 호스팅 대상 패널을 미리 알 수 없습니다. 즉, UserControl 자체를 'on-the-fly'로 작성할 수 있기 때문입니다 (사용자가 ListBox 항목 더 많은 잠재적 인 호스팅 패널이 생성됨). 내가 좀 더 유연한 방법으로 "DesignerSerializationVisibility"와 "EnableDesignMode"방법을 사용하여 시도,하지만 여전히 전술로 실행하는 것 한

오류 '자식이 부모의 자식 컨트롤되지 않습니다'.

이 모든 것이 의미가 있기를 바랍니다. 하여 ListBoxPanelControl의 이벤트가, 내가 통해 ("EnableDesignMode"전화 "OnControlAdded"에, 그리고 ...

[ 
    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 클래스 내에 : 코드는 현재 다음과 같이 보입니다 현재 활성화 된 패널에 대한 "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에 컨트롤을 추가 할 수 있습니다.이 컨트롤은 대상 호스팅 컨트롤 자체가 자식 컨트롤이며, UserControl 자체가 동적이며 온더 플라이 (on-the-fly)로 빌드되는 경우?

도움/의견 통하 주셔서 감사합니다! 토니.

답변

1

미래의 모든 독자에게 유용 할 경우를 대비하여 업데이트를 제공 할 것이라고 생각했습니다. 나는 "이 자식의 자식 제어가 아니다"라는 오류를 해결할 수있었습니다. 문제는 내 "현재 활성화 된"패널에 "EnableDesignMode"를 호출하여 컨트롤을 그 위에 놓을 수있게했지만 "EnableDesignMode"메서드의 요구 사항 중 하나가 그 것을 인식하지 못했습니다. "The 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(); 
} 

희망 ... 이것에 대한

+0

감사합니다. 나는 나 자신과 비슷한 무엇인가를 연구하고 있는데 이것은 도움이 될 수있다. 한 가지주의 할 점은 예외가 있는지 여부에 관계없이 finally 블록이 실행됩니다. 취소 한 후에 designerTransaction.Commit()을 호출해도 괜찮습니까? – TrespassersW

+0

디자이너 호스트는 어디에서 작동합니까? 그리고이 코드는 어디에서 실행 했습니까? 디자이너 클래스에 있었나요? – ernest