托管UserControl设计器的ToolStripControlHost不会发生序列化

时间:2009-09-02 17:19:23

标签: c# .net visual-studio winforms serialization

我目前正在开发一个应用程序,我想在上下文菜单中显示UserControl。我能够(使用ToolStripControlHost实现这一点)。显示在(NumericUpDownToolStripItem代码)中:下面是对象的代码(用VC ++。net 2.0编写)。注意:在这方面存在半类似的SO问题,但似乎没有一个问题涉及序列化用户控件,只是处理用户控件中的标准对象。

对象后面显示的是实际usercontrol的代码,它是带有标签的usercontrol和numericupdown控件。

问题:当我为我的应用程序加载设计器时,我可以添加我的NumericUpDownToolStripItem就好了,但是,当我打开使用外露属性来编辑我的usercontrol时,没有任何数据被序列化为InitializeComponent方法我的NumericUpDownToolStripItem对象。这样做的结果是我的控件加载与运行时的所有默认值。每次我重新加载表单时,修改都会丢失。

我尝试使用位于On Msdn的TypeConverter教程,但它无法正常工作。一切都编译得很好,除了我的对象在设计网格中变得完全灰暗(只是访问者属性,而不是整个menupic)。我注意到的另一个问题是这个方法并不是专为UserControls设计的,它可能有几个不同的可修改属性,并且每个都不可能有重载。

所以,我有以下问题:

  1. 我正在做的是实践,还是我的结构偏离了规范。我确信属性中有很多冗余。
  2. 序列化另一个UserControl \ toolstriphost“parent”中包含的usercontrol'child'的正确方法是什么。 'child'中的任何属性都是简单值(字符串,小数等)。
  3. 当没有实现TypeConverter类时,每次我更改一个属性(例如标签文本)时,对象的绘画都会被抬起并表现得很奇怪,直到我重新编译上下文\菜单或表单。是否有正确的方法通知设计师重绘,因为我做了改变? (我使用的无效最好是狡猾的。)
  4. 提前致谢。我将继续研究这个并更新问题。

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

2 个答案:

答案 0 :(得分: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 :(得分: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);
   }   
};