2009-09-02 4 views
5

Ich entwickle gerade eine Anwendung, in der ich ein UserControl in einem Kontextmenü anzeigen möchte. Ich konnte (etwas mit ToolStripControlHost erreichen). Angezeigt in (NumericUpDownToolStripItem-Code): Unten ist Code für das Objekt (in VC++ .net 2.0 geschrieben). Hinweis: Es gibt semi-ähnliche SO-Fragen zu diesem Thema, aber keines scheint sich mit der Serialisierung von Benutzersteuerelementen zu befassen, sondern nur ein Standardobjekt in den Benutzersteuerelementen.ToolStripControlHost Hosting eines UserControl-Designers Serialisierung tritt nicht auf

Nach dem Objekt angezeigt wird der Code für die tatsächliche Benutzersteuerung, die eine Benutzersteuerung mit einem Label und eine numerische updown-Steuerelement ist.

Das Problem: Wenn ich den Designer für meine Anwendung laden, kann ich meine NumericUpDownToolStripItem problemlos hinzufügen, aber wenn ich die exposed-Eigenschaft zum Bearbeiten meiner Benutzersteuerung öffnen, wird keine dieser Daten in die InitializeComponent-Methode serialisiert meines NumericUpDownToolStripItem-Objekts. Der Effekt davon ist, dass mein Steuerelement mit allen Standardwerten zur Laufzeit geladen wird. Und jedes Mal, wenn ich mein Formular neu lade, gehen die Änderungen verloren.

Ich habe versucht, mit der TypeConverter Tutorial On Msdn, aber es hat nicht richtig funktioniert. Alles kompiliert gut, außer mein Objekt wurde im Design-Grid vollständig ausgegraut (nur die Accessor-Eigenschaft, nicht die gesamte Menupic). Ein anderes Problem, das ich bemerkt habe, ist, dass diese Methode nicht speziell für UserControls entworfen wurde, die mehrere verschiedene modifizierbare Eigenschaften haben können und möglicherweise nicht für jede eine Überladung haben können. So

, ich habe folgende Fragen:

  1. Ist das, was ich tue, praktisch, oder ist meine Struktur Weg-off der Normen. Ich bin mir sicher, dass die Attribute sehr redundant sind.
  2. Was ist die richtige Methode zum Serialisieren eines Benutzersteuerelements 'Kind' in einem anderen UserControl \ toolstriphost 'Eltern' enthalten. Alle Eigenschaften in 'Kind' sind einfache Werte (Strings, Dezimalzahlen usw.).
  3. Wenn die TypeConverter-Klasse nicht implementiert ist, jedes Mal wenn ich eine Eigenschaft änderte (ein Label-Text zum Beispiel), würde das Bild des Objekts alle aufgebockt werden und sich merkwürdig verhalten, bis ich das Kontextmenü oder das Formular wiederbelebte. Gibt es eine gute Möglichkeit, den Designer zu überarbeiten, weil ich eine Änderung vorgenommen habe? (Ich benutzte Invalidate, die bestenfalls zweifelhaft war).

Vielen Dank im Voraus. Ich werde das weiter erforschen und die Frage auf dem Laufenden halten.

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

Sorry für die Thread Auferstehung, aber dies scheint der einzige Beitrag, die ich mit genau diesem Problem zu tun finden. Ich frage mich, was Sie getan haben, um Ihren Control-Host-Designer sichtbar zu machen - ich kann es nicht erscheinen lassen, dass Visual Studio es anzeigt, egal was ich mache. Ich habe alles angewendet, von dem MSDN behauptet, dass es Designer-Unterstützung ermöglichen soll, und nichts. Einige Hinweise würden sehr geschätzt werden. –

+0

Ich erinnere mich nicht genau, was ich getan habe, aber ich weiß, dass diese Kontrolle freigegeben wurde und "im Produkt" ist. Ich werde versuchen, den Code aufzuspüren und das Steuerelement selbst erneut zu posten, um festzustellen, ob es einen Unterschied gibt. – greggorob64

+1

Überprüfen Sie meine neue Post unten, ich postete meine aktuelle Arbeit Setup – greggorob64

Antwort

1

Meine neueste, „arbeite“ Lösung:

//////////////////////////////////////////////////////////////////////////////////////////////////// 
/// <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

Nun, nach viel suchen, fand ich meine Antwort. Meine Methodik war in Ordnung, abgesehen von einem großen Problem: Ich brauchte keine Typwandler. Mein Problem war die Notwendigkeit für einen benutzerdefinierten CodeDomConverter. Unten ist meine Lösung dargestellt.

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); 
    } 
};