2009-09-02 3 views
5

현재 컨텍스트 메뉴 내에 UserControl을 표시하려는 응용 프로그램을 개발 중입니다. 나는 (다소 ToolStripControlHost를 사용하여 이것을 달성 할 수 있었다). 아래 그림은 (NumericUpDownToolStripItem code)입니다 : 아래는 VC++ .net 2.0으로 작성된 객체의 코드입니다. 참고 : 거기에 비슷한 세미 질문이 있지만 serialize하는 usercontrols, usercontrols 그냥 표준 개체를 다루는 것 같습니다.UserControl 디자이너를 호스팅하는 ToolStripControlHost Serializing이 발생하지 않습니다.

실제 usercontrol (레이블이있는 usercontrol) 및 numericupdown 컨트롤에 대한 코드가 개체 다음에 표시됩니다.

문제 : 내 응용 프로그램에 대한 디자이너를로드 할 때 NumericUpDownToolStripItem을 잘 추가 할 수 있지만 노출 된 속성을 사용하여 내 usercontrol을 편집 할 때 해당 데이터가 InitializeComponent 메서드에 직렬화되지 않습니다 내 NumericUpDownToolStripItem 개체 이것의 효과는 런타임에 모든 기본값으로 컨트롤이로드된다는 것입니다. 그리고 내 양식을 다시로드 할 때마다 수정 사항이 손실됩니다.

On Msdn에 위치한 TypeConverter 자습서를 사용해 보았지만 올바르게 작동하지 않았습니다. 내 객체가 디자인 격자에서 완전히 회색으로 된 것을 제외하고는 모든 것이 잘 컴파일되었습니다 (전체 매뉴 픽이 아닌 액세서 속성 만). 내가 알아챈 또 다른 문제점은이 메서드가 여러 다른 수정 가능한 속성을 가질 수있는 UserControls 용으로 특별히 설계되지 않았으며 각각에 대해 과부하를 가질 수 없다는 점입니다.

그래서, 나는 다음과 같은 질문이 :

  1. 내가 실제 뭘하는지, 아니면 내 구조 방법 오프 규범이다. 속성에 많은 중복성이있을 것입니다.
  2. 다른 UserControl \ toolstriphost '부모'에 들어있는 사용자 정의 컨트롤 '하위'를 serialize하는 올바른 방법은 무엇입니까? '자식'의 모든 속성은 단순한 값 (문자열, 소수점 등)입니다.
  3. TypeConverter 클래스가 구현되지 않았을 때, 속성 (예 : 레이블 텍스트)을 변경할 때마다 컨텍스트 메뉴 나 양식을 다시 볼 때까지 객체의 페인팅이 모두 종료되어 이상하게 동작합니다. 내가 변경했기 때문에 디자이너에게 다시 칠하도록 알릴 수있는 적절한 방법이 있습니까? (나는 최고로 dodgy 인 invalidate를 사용했다).

미리 감사드립니다. 나는 이것을 계속 연구하고 질문을 계속 업데이트 할 것입니다.

NumericUpDownToolStripItem Class: 
    [ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability::All)] 
    public ref class NumericUpDownToolStripItem : public ToolStripControlHost 
    { 
     public: 
     [DesignerSerializationVisibility(DesignerSerializationVisibility::Content | 
      DesignerSerializationVisibility::Visible)] 
     property LabeledNumericUpDown ^LabeledNumericUpDownControl 
     { 
     LabeledNumericUpDown ^get() { return (LabeledNumericUpDown^)this->Control; } 
     } 

     public: NumericUpDownToolStripItem(void) : 
      ToolStripControlHost(gcnew LabeledNumericUpDown()) {} 

     protected: void OnSubscribeControlEvents(Control ^control) new { //irrelevant to question } 
     protected: void OnUnsubscribeControlEvents(Control ^control) new { //irrelevant to question }  
    }; 

public ref class LabeledNumericUpDown : public UserControl 
{ 
    public: [ DesignerSerializationVisibility(DesignerSerializationVisibility::Content | 
    DesignerSerializationVisibility::Visible)] 
    property String ^DisplayText { 
     String ^get() { 
     return this->label->Text; 
     } 
     void set(String ^val) { 
     if(this->label->Text != val) 
     { 
      this->label->Text = val; 
      this->Invalidate(); 
     } 
     } 
    } 

//constructor 
//destructor 
//initiailecomponent 
}; 
+0

스레드 부활 죄송합니다,하지만 내가이 정확한 문제를 다루는 찾을 수있는 유일한 포스트 것으로 보인다. 나는 당신이 컨트롤 호스트 디자이너를 보이게하기 위해 무엇을했는지 궁금합니다 - 내가하는 일에 상관없이 Visual Studio에서 그것을 표시 할 수는없는 것 같습니다. MSDN 클레임이 디자이너 지원을 가능하게하는 모든 것을 적용했습니다. 어떤 조언을 많이 주시면 감사하겠습니다. –

+0

나는 내가 한 일을 정확하게 기억하지 못한다. 그러나 나는이 통제가 풀려 났으며 "제품 안에있다"는 것을 알고있다. 코드를 추적하고 컨트롤 자체를 다시 게시하여 차이가 있는지 확인하려고합니다. – greggorob64

+1

아래 새 게시물을 확인하십시오, 현재 작업 설정을 다시 게시했습니다. – greggorob64

답변

1

내 가장 최근의 "작업"솔루션 :

//////////////////////////////////////////////////////////////////////////////////////////////////// 
/// <summary> 
/// This Usercontrol is a simple label coupled with a numericupdown. The class following 
/// it will wrap this item in toolstrip container so that it can be part of a contextmenu 
/// </summary> 
//////////////////////////////////////////////////////////////////////////////////////////////////// 
[DesignerSerializer(CustomCodeDomSerializer<LabeledNumericUpDown^>::typeid, CodeDomSerializer::typeid)] 
public ref class LabeledNumericUpDown : UserControl 
{ 
    public: event EventHandler ^NumericUpDownValueChanged; 

    public: [Category("Custom Information"), Description(L"Text to display"), 
      DefaultValue(L"Default Text"), Browsable(true), Localizable(true), NotifyParentProperty(true)] 
    property String ^DisplayText 
    { 
     String ^get(); 
     void set(String ^val); 
    } 

    public: [Category("Custom Information"), Description(L"NumericUpDown Value"), 
      DefaultValue(1), Browsable(true), Localizable(true), NotifyParentProperty(true)] 
    property Decimal UpDownValue 
    { 
     Decimal get(); 
     void set(Decimal val); 
    } 

    public: [Category("Custom Information"), Description(L"NumericUpDown Maximum"), 
      DefaultValue(100), Browsable(true), Localizable(true), NotifyParentProperty(true)] 
    property Decimal UpDownMaximum 
    { 
     Decimal get(); 
     void set(Decimal val); 
    } 

    public: [Category("Custom Information"), Description(L"NumericUpDown Minimum"), 
      DefaultValue(0), Browsable(true), Localizable(true), NotifyParentProperty(true)] 
    property Decimal UpDownMinimum 
    { 
     Decimal get(); 
     void set(Decimal val); 
    } 

    private: bool SupressEvents; 
    public: Void UpDownValueSet_NoEvent(int Val); 
    private: Void numericUpDown_ValueChanged(Object ^sender, EventArgs ^e); 
    public: LabeledNumericUpDown(void); 
    private: System::Windows::Forms::NumericUpDown^ numericUpDown; 
    private: System::Windows::Forms::Label^ label; 
    private: System::Windows::Forms::TableLayoutPanel^ tableLayoutPanel1; 
    private: System::ComponentModel::Container ^components; 
    #pragma region Windows Form Designer generated code 
    void InitializeComponent(void); 
}; 

//////////////////////////////////////////////////////////////////////////////////////////////////// 
/// <summary> CustomCodeDomSerializer 
/// This is a specialized usercontrol designed to incapsulate another usercontrol (in this case a 
/// NumericUpDownToolStripItem. In order to use this class, you must copy this entire class and 
/// create a new object. (You can do this right underneath your usercontrol in the same file 
/// if you wish. You must specifiy the type of your object every place its mentioned. 
/// 
/// To Note: The toolbox bitmap is what the icon will look like. You can specify any old control. 
/// It is possible to use a custom icon, but I can't figure out how. 
///</summary> 
/// 
/// <value> The tool strip control host. </value> 
//////////////////////////////////////////////////////////////////////////////////////////////////// 

[ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability::All), 
ToolboxBitmap(::NumericUpDown::typeid)] 
public ref class NumericUpDownToolStripItem : ToolStripControlHost 
{ 
    //replace this type 
    private: LabeledNumericUpDown ^_Control; 

    public: [Category("Object Host"), Description(L"Hosted usercontrol object"), 
    DisplayName("UserControl Object"), Browsable(true), NotifyParentProperty(true), 
    DesignerSerializationVisibility(DesignerSerializationVisibility::Content)] 
    //replace this properties type 
    property LabeledNumericUpDown ^UserControlObject 
    { 
    //replace this properties return type 
    LabeledNumericUpDown ^get() { return this->_Control; } 
    } 

    public: NumericUpDownToolStripItem(void) : 
     System::Windows::Forms::ToolStripControlHost(gcnew FlowLayoutPanel()) 
    { 
     //replace this constructor type 
     _Control = gcnew LabeledNumericUpDown(); 

     //don't touch this 
     FlowLayoutPanel ^thePanel = (FlowLayoutPanel ^)this->Control; 
     thePanel->BackColor = Color::Transparent; 
     thePanel->Controls->Add(_Control); 
    } 
}; 
1

글쎄, 많이 검색 한 후, 나는 내 대답을 발견했다. 내 방법론은 하나의 큰 문제를 제외하고는 괜찮았다. 나는 타이 커콘을 전혀 필요로하지 않았다. 내 문제는 사용자 정의 CodeDomConverter에 대한 필요성이었다. 다음은 내 솔루션입니다.

generic<typename T> 
    ref class CustomCodeDomSerializer : CodeDomSerializer 
    { 
    public: virtual Object ^Deserialize(IDesignerSerializationManager ^manager, Object ^codeObject) override 
     { 
      // This is how we associate the component with the serializer. 
      CodeDomSerializer ^baseClassSerializer = (CodeDomSerializer^)manager-> 
      GetSerializer(T::typeid->BaseType, CodeDomSerializer::typeid); 

      //This is the simplest case, in which the class just calls the base class 
      // to do the work. 
      return baseClassSerializer->Deserialize(manager, codeObject); 
     } 

     public: virtual Object ^Serialize(IDesignerSerializationManager ^manager, Object ^value) override 
     { 
      //Associate the component with the serializer in the same manner as with 
      // Deserialize 
      CodeDomSerializer ^baseClassSerializer = (CodeDomSerializer^)manager-> 
      GetSerializer(T::typeid->BaseType, CodeDomSerializer::typeid); 

      Object ^codeObject = baseClassSerializer->Serialize(manager, value); 

      //Anything could be in the codeObject. This sample operates on a 
      // CodeStatementCollection. 
      if (dynamic_cast<CodeStatementCollection^>(codeObject)) 
      { 
      CodeStatementCollection ^statements = (CodeStatementCollection^)codeObject; 

      // The code statement collection is valid, so add a comment. 
      String ^commentText = "This comment was added to this Object by a custom serializer."; 
      CodeCommentStatement ^comment = gcnew CodeCommentStatement(commentText); 
      statements->Insert(0, comment); 
      } 
      return codeObject; 
     } 

}; 




//////////////////////////////////////////////////////////////////////////////////////////////////// 
/// <summary> 
/// This Usercontrol is a simple label coupled with a numericupdown. The class following 
/// it will wrap this item in toolstrip container so that it can be part of a contextmenu 
/// </summary> 
//////////////////////////////////////////////////////////////////////////////////////////////////// 
[DesignerSerializer(CustomCodeDomSerializer<LabeledNumericUpDown^>::typeid, CodeDomSerializer::typeid)] 
public ref class LabeledNumericUpDown : UserControl 
{ 
    public: event EventHandler ^NumericUpDownValueChanged; 

    public: [Category("Custom Information"), Description(L"Text to display"), 
      DefaultValue(L"Default Text"), Browsable(true), Localizable(true), NotifyParentProperty(true)] 
    property String ^DisplayText 
    { 
     String ^get() 
     { 
     return this->label->Text; 
     } 
     void set(String ^val) 
     { 
     this->label->Text = val; 
     if(this->DesignMode || 
      LicenseManager::UsageMode == LicenseUsageMode::Designtime) 
      this->Invalidate(); 

     } 
    } 
    //designer stuff not important 
} 




[ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability::All), 
ToolboxBitmap(::NumericUpDown::typeid)] 
public ref class NumericUpDownToolStripItem : ToolStripControlHost 
{ 
    //replace this type 
    private: LabeledNumericUpDown ^_Control; 

    public: [Category("Object Host"), Description(L"Hosted usercontrol object"), 
    DisplayName("UserControl Object"), Browsable(true), NotifyParentProperty(true), 
    DesignerSerializationVisibility(DesignerSerializationVisibility::Content)] 
    //replace this properties type 
    property LabeledNumericUpDown ^UserControlObject 
    { 
    //replace this properties return type 
    LabeledNumericUpDown ^get() { return this->_Control; } 
    } 

    public: NumericUpDownToolStripItem(void) : 
     System::Windows::Forms::ToolStripControlHost(gcnew FlowLayoutPanel()) 
    { 
     //replace this constructor type 
     _Control = gcnew LabeledNumericUpDown(); 

     //don't touch this 
     FlowLayoutPanel ^thePanel = (FlowLayoutPanel ^)this->Control; 
     thePanel->BackColor = Color::Transparent; 
     thePanel->Controls->Add(_Control); 
    } 
}; 
관련 문제