2009-09-02 7 views
5

Obecnie rozwijam aplikację, w której chcę wyświetlić UserControl w menu kontekstowym. Byłem w stanie (nieco osiągnąć to za pomocą ToolStripControlHost). Wyświetlany w (NumericUpDownToolStripItem kod): poniżej jest kod dla obiektu (napisany w VC++ .net 2.0). Uwaga: Na tym są częściowo podobne pytania SO, ale żaden nie wydaje się zajmować serializacją kontroli użytkownika, tylko standardowym obiektem w kontrolkach użytkownika.ToolStripControlHost hosting projektanta UserControl Serializacja nie pojawi się

Wyświetlany po obiekcie jest kod rzeczywistego sterowania użytkownika, który jest sterowaniem użytkownika z etykietą i kontrolką numericupdown.

Problem: Kiedy ładuję projektanta do mojej aplikacji, mogę dodać mój NumericUpDownToolStripItem dobrze, jednak gdy otworzę użycie, aby odsłonić go w sposób umożliwiający edycję mojej kontroli użytkownika, żadna z tych danych nie jest serializowana do metody InitializeComponent z mojego obiektu NumericUpDownToolStripItem. Efektem tego są moje obciążenia sterujące z wszystkimi ustawieniami domyślnymi w czasie wykonywania. Za każdym razem, gdy ponownie ładuję formularz, modyfikacje są tracone.

Próbowałem używać samouczka TypeConverter znajdującego się pod adresem On Msdn, ale nie działał poprawnie. Wszystko skompilowane w porządku, z wyjątkiem tego, że mój obiekt stał się całkowicie szary w siatce projektowej (tylko właściwość akcesora, a nie cały menupik). Kolejnym problemem, który zauważyłem, jest to, że ta metoda nie jest specjalnie zaprojektowana dla UserControls, która może mieć kilka różnych modyfikowalnych właściwości i nie może mieć przeciążenia dla każdej z nich.

Więc mam następujące pytania:

  1. Czy to, co robię, jest praktyczny, czy mój sposób struktura-off normy. Jestem pewien, że w atrybutach jest dużo redundancji.
  2. Jaka jest prawidłowa metoda serializowania elementu potomnego kontrolki użytkownika zawartego w innym obiekcie macierzystym UserControl \ toolstriphost. Wszystkie właściwości w podrzędnym są prostymi wartościami (ciągi, ułamki dziesiętne itd.).
  3. Gdy klasa TypeConverter nie jest zaimplementowana, za każdym razem, gdy zmieniłem właściwość (tekst etykiety na przykład), obraz obiektu zostałby wywołany i zachowywał się dziwnie, dopóki nie zmieniłem kontekstu \ menu lub formularza. Czy istnieje odpowiedni sposób poinformowania projektanta o przemalowaniu, ponieważ dokonałem zmiany? (Użyłem unieważnienia, które w najlepszym przypadku było podejrzane).

Z góry dziękuję. Zamierzam kontynuować to badanie i aktualizować pytanie.

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

Niestety na zmartwychwstanie wątku, ale to wydaje się być jedynym postu mogę znaleźć do czynienia z dokładnie tej kwestii. Zastanawiam się, co zrobiłeś, aby twój projektant hosta kontrolnego był widoczny - nie wydaje mi się, żeby to studio graficzne go wyświetlało, bez względu na to, co robię. Zastosowałem wszystko, co twierdzi firma MSDN, aby umożliwić wsparcie projektanta i nic. Niektóre wskaźniki byłyby bardzo cenne. –

+0

Nie pamiętam dokładnie, co zrobiłem, ale wiem, że ta kontrola została wydana i jest "w produkcie". Zamierzam spróbować wyśledzić kod i odświeżyć kontrolę, aby sprawdzić, czy jest jakaś różnica. – greggorob64

+1

Sprawdź mój nowy wpis poniżej, Prześlij moją aktualną konfigurację roboczą – greggorob64

Odpowiedz

1

Moja najnowsza, „praca” rozwiązanie:

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

Po wielu poszukiwaniach znalazłem odpowiedź. Moja metodologia była w porządku, z wyjątkiem jednego poważnego problemu: w ogóle nie potrzebowałem typokonwerterów. Moim problemem było zapotrzebowanie na niestandardowy CodeDomConverter. Poniżej pokazane jest moje rozwiązanie.

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); 
    } 
}; 
Powiązane problemy