ToolStripControlHost on which the UserControl designer is hosted Serialization will not happen

I am currently developing an application in which I want to display UserControl inside the context menu. I managed (to achieve this somewhat using ToolStripControlHost). Shown in (NumericUpDownToolStripItem code): below is the code for the object (written in VC ++ .NET 2.0). Note. There are semi-similar SO questions on this, but none of them seem to be related to serializing user controls, but simply a standard object in usercontrols.

The object shown below is the actual user control code, which is tagged user control, and the numericupdown control.

Problem: when I load the constructor for my application, I can add my NumericUpDownToolStripItem just fine, however, when I open use to efficiently edit my user control, none of this data is serialized in the InitializeComponent method for my NumericUpDownToolStripItem object. The effect of this is my control loads with all the default values ​​at runtime. And every time I reload the form, the changes are lost.

I tried using the TypeConverter tutorial located On Msdn , but it did not work properly. Everything compiled just fine, except that my object is completely saddled in the design grid (just an accessor property, not all menupic). Another issue that I noticed is that this method is not specifically designed for UserControls, which can have several different mutable properties and cannot have overloads for each.

So, I have the following questions:

  • This is what I do practical, or my structure goes beyond the norm. I am sure there is a lot of redundancy in attributes.
  • usercontrol, UserControl\toolstriphost. "" (, ..).
  • TypeConverter , , (, ), , . , ? ( , ).

. .

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
};
+5
2

, "" :

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

, . , : typeconverters. 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);
   }   
};
+1

All Articles