2011-09-05 6 views
0

해결 방법이있는 펑키 한 문제가 있지만 가능하면 코드를 비슷하게 유지하려고합니다. 문제는 null 일 수도 있고 없을 수도있는 사용자 컨트롤에 대한 기본 클래스의 특정 변수를 중심으로합니다.WinForm 사용자 정의 컨트롤을 인스턴스화 할 때 기본 클래스가 항상 호출되지 않음

기본적으로 사용자 컨트롤에 기본 폼 속성에 대한 액세스 권한이 있고 기본 폼에서 메서드를 호출 할 수 있도록 기본 폼 클래스의 인스턴스를 가져 오는 단일 기본 클래스를 가진 많은 사용자 컨트롤이 있습니다. 여기에 조각입니다 (this.frmParent는 공개 멤버) : 다음

private void ucBase_Load(object sender, EventArgs e) 
    { 
     // Establish the link to the main form. 
     this.frmParent = FindForm() as frmMain; 
    } 

각 사용자 제어 주이 기본 클래스 :

public partial class ucLiberty : ucBase 

그런 다음 기본 폼에, 나는 사용자 정의 컨트롤을 호출 할 수 있습니다 이 같은 어떤 이유로

   ucLiberty Liberty = new ucLiberty(); 
       IQDevicePath = Liberty.GetIQDrivePath(); 

, I는 사용자 제어를 초기화 할 때 (이 경우는 기본 형태의)베이스 클래스에서 frmParent 변수 또는 비 NULL 값으로 채워지지 않을 수있다.

사용자 컨트롤의로드 이벤트가 발생하지 않은 것으로 나타났습니다. CreateControl()이라는 컨트롤의 생성을 강제하기로되어있는 메서드를 발견하고, 디버거에서 실행을 추적했을 때 frmParent를 채우려는 기본 클래스에 도착했을 때 내로드 이벤트가 시작되었습니다. FindForm()은 항상 null이 아닌 값을 반환하지는 않습니다.

나는이 문제가없는 다른 사용자 컨트롤이 있는데, 그 차이점은 일부 사용자 컨트롤에는 자식 컨트롤이 있고 일부 컨트롤에는 자식 컨트롤이 없다는 것입니다. 자식 컨트롤이없는 사람에게는이 문제가 있습니다.

내 해결에 실패하는 사용자 컨트롤 FindForm() 모니터링 할 수 있으며, 해당 사용자 컨트롤의로드 이벤트에, 기본 폼의 생성자를 호출,이 같은으로 값을 할당 :

this.frmParent = new frmMain(); 

그러나 , 나는 여전히로드 이벤트가 발생하도록 CreateControl()을 호출해야하며, 미래의 유지 관리자에게 다른 동작 요구 사항에 대한 명시 적 지식이 필요하다는 생각이 맘에 들지 않습니다. 다시 말해서, 사용자 컨트롤이 모두 유지 보수를 단순하게 유지하는 것과 같은 방식으로 작동하도록하고 싶습니다.

필자는 코드를 찢어 버리고 사용자 정의 컨트롤의로드 이벤트가 발생하거나 실행되지 않을 때 왜 사용자 컨트롤 기본 클래스에서 FindForm() 호출이 실패하는지 이해할 수 없습니다.

누구든지 이러한 문제를 해결하는 방법에 대한 아이디어가 있습니까? 감사.

답변

2

사용자 컨트롤이 자신이 배치 된 양식을 인식하도록하여 사용자가 심각한 OOP 죄를 저지르고 있습니다. 이라고 가정하면은 해당 컨테이너를 신경 쓰지 않는 독립적 인 클래스가됩니다. 이벤트를 사용하여 컨테이너가 관심을 가질만한 클래스에서 일어난 일을 인식하게합니다. Winforms의 표준 컨트롤 중 하나에 의해 문자. TextBox는 어떤 형태의 폼이 떨어 졌는지 결코 신경 쓰지 않습니다.

그건 이론입니다. 연습은 자주 깨끗하지 않습니다. 실행중인 문제는 다른 이유로 OnLoad 메서드 (일명 Load 이벤트)가 실행된다는 것입니다. 네이티브 Windows 핸들이 생성되면 실행됩니다.어떤 은 보통이 발생하면 Show() 메서드 호출에 의해 트리거 된 폼의 창을 만들 때 발생합니다. 어떤 양식의 IntializeComponent() 메서드 뒤에.

사용자 정의 컨트롤의 생성자에 Handle 속성에 값이 있어야하는 코드가 있으면 Winforms는 컨트롤에 Windows 핸들을 만들고 Load 이벤트를 발생시킵니다. 폼의 InitializeComponent() 메서드가 Controls.Add() 메서드를 호출 할 수있는 기회가 오기까지는 너무 이르렀습니다. Parent 속성은 아직 양식을 참조하지 않습니다. FindForm()에서 Kaboom.

디버거로 진단하기 쉽습니다. 사용자 정의 컨트롤의 OnLoad 메서드에 중단 점을 설정하십시오. 스택 추적은 핸들 생성을 트리거 한 명령문으로 바로 이동합니다.

+0

나는 VS (InitializeComponent())에 의해 놓여진 것 외에는 사용자 정의 컨트롤 생성자에 아무것도 없다. 사용자 정의 컨트롤에는 컨트롤이없고 코드 만 있습니다. 로드 이벤트는 컨트롤이 인스턴스화 될 때 실행되지 않고 첫 번째 메서드가 호출 될 때 호출되지 않지만 두 번째 메서드가 호출되고 FindForm()이 null을 반환하면 호출됩니다. – MikeMalter

0

몇 개의 기본 폼 인스턴스가 있습니까? 만약 당신이 오직 하나만 가지고 있다면, 당신은 그것을 가질 수 있습니다.

public class frmMain : Form 
{ 
    private static frmMain s_Singleton; 

    public static frmMain Singleton 
    { 
      get 
      { 
       if (s_Singleton == null) s_Singleton = new frmMain(); 
       return s_Singleton; 
      } 

    } 
} 

그래서 그 대신 지금까지 직접 생성자를 호출, 참조에 대한 frmMain.Singleton 전화 (특히, 심지어에서 (!) 당신의 Program.cs를 양식이 처음 지어진 대부분입니다.) 또한 사용자의 컨트롤에 frmMain.Singleton을 호출하여 사용할 수있는 메인 폼에 대한 전체 참조를 가질 수 있습니다.

ucBase_Load가로드되지 않는 이유에 대해서는 무조건적인 추측을 통해 구체적인 사용자 그리고 어떻게 든 기본 핸들러가 실행되지 않게합니다. 이 경우 구체적인 사용자 정의 컨트롤의 이벤트 처리기에 base.OnLoad()을 추가하십시오.

FindForm이 작동하지 않는 이유는 사용자 정의 컨트롤의 생성자가 완료되기 전에 메서드가 호출 되었기 때문일 수 있습니다. 이럴 가능성은 없지만 코드를 보지 않고도 말하기는 어렵습니다. 이것이 문제가되는 이유는 컨트롤의 부모 등이 생성자에 설정되어 있기 때문입니다. 하지만 Load 이벤트에서 처리하고 있기 때문에 가능성은 희박합니다. 논리를 OnParentChanged 이벤트로 이동하여이 이론을 검증 할 수 있습니다. 그런데

, 당신의 작업은 주위 (도시되지 않습니다)을 새로운 기본 폼 인스턴스를 생성, 매우 더러운, 그것은 당신에게 당신의 기본 폼에 대한 참조를 제공하지 않는 것 같다.