Hello everyone!  I'm having a problem with a WebControl that I'm 
designing
for a Menu.  I've been at it for about 3 weeks now, and can't seem to 
get
around this problem.  So I'm hoping that someone can help me ...

My environment:  VS 2003 v7.1.3088, Win2K v5.0.2195 SP3, IE6 
v6.0.2800.1106
browser.

I have a class (C3Menu) derived from WebControl, with a property 
(MenuItems)
that is a collection of menu items.  The collection property is 
defined as a
class which inherits from CollectionBase.  I also have a Designer 
associated
to the C3Menu class which allows design-time support.
See the code below for more details.

The control is generating properly - the menu items are being 
persisted to
the HTML view, and the control is rendering ok in both design view 
and at
run-time.  An ellipse button appears next to the MenuItems 
collection, which
allows me to add / remove items from the collection via the standard
collection editor - everything seems normal!

The problem is when I use the following sequence of events:
1) I run my test application to bring the page up in IE6, everything 
looks
ok.
2) I close the page to return back to the VS editor.
3) I single-click my control to display the properties in the property
browser.
4) I click the ellipses button to edit the menuitems collection.
5) I click Add to add a new item to the collection - I see the item 
added in
the left pane of the collection editor.
6) I click Ok to return to VS view.
7) The item(s) I just added do not persist to the HTML view, nor to 
the
design view!

It gets better!  If I click to the HTML view and back to the Design 
view,
the design view gets updated with the new items - but if I click back 
to the
HTML view, the items are still not persisted!  If I go through the 
above
sequence of events again (immediately after the HTML/Design view 
switch), I
still see my new items I added - and when I add another item (via 
collection
editor) and select Ok to return to design view it updates it with ALL 
my new
items I added and the items are persisted in the HTML view!

It gets even weirder!  I can go through the above sequence of events, 
but if
I select another web control between steps 2 and 3 (a Label for 
instance)
everything is persisted correctly.

I originally wrote my own custom collection editor and was having the 
same
problem, so I decided just to utilize the standard collectioneditor - 
with
the same results.  After all of the reading I've done, I'm thinking 
it has
something to do with a TypeConverter but am not for sure.  I added 
the type
converter on the MenuItem (collection item) definition, but it did 
not seem
to help.

Any ideas?  I would be happy to send the code for anyone to look at, 
as this
is more of a learning experience for me than anything.  This is my 
first
design-time control writing attempt - any help would be appreciated.

Thanks,

Todd Lucas
email:  Todd.Lucas -at- cox.net



Code snippets:


----------------------------------------------------------------------
------
-
C3Menu.vb - C3Menu Class Definition


Imports System.ComponentModel
Imports System.ComponentModel.Design
Imports System.Web.UI
Imports System.Collections.Specialized
Imports System.Web.UI.WebControls.CommandEventArgs
Imports System.Web.UI.WebControls
Imports System.Drawing
Imports System.Drawing.Design

Namespace C3WebControls

 <DefaultProperty("MenuItems"), DefaultEvent("ItemClick"), _
  Description("Server Control - Menu Definition."), _
  ParseChildren(True), PersistChildren(False), _
  Designer(GetType(C3WebControls.C3Menu_Designer)), _
  ToolboxData("<{0}:C3Menu runat=server></{0}:C3Menu>")> _
  Public Class C3Menu : Inherits System.Web.UI.WebControls.WebControl
...
  ' Menu items storage:
  Dim _menuitems As New C3MenuItems
...
  <Bindable(False), Category("Menu Properties"), NotifyParentProperty
(True),
_
  DesignerSerializationVisibility
(DesignerSerializationVisibility.Content),
_
  PersistenceMode(PersistenceMode.InnerProperty), _
  Editor(GetType(C3WebControls.C3MenuItem_CollectionEditor),
GetType(UITypeEditor)), _
  Description("Collection of Menu Items this object will display.")> _
  Public ReadOnly Property [MenuItems]() As C3MenuItems
   Get
    Return _menuitems
   End Get
   'This property has no SET value!
  End Property
...
----------------------------------------------------------------------
------
-
C3MenuItems.vb - C3MenuItems Class Definition

Imports System.Web.UI
Imports System.Globalization
Imports System.ComponentModel
Imports System.ComponentModel.Design.Serialization

Namespace C3WebControls

 ' Menu Item Collection Class:
 <Description("Menu Item Collection Definition.")> _
 Public Class C3MenuItems : Inherits CollectionBase

  Default Public Property Item(ByVal index As Integer) As C3MenuItem
   Get
    Return DirectCast(MyBase.List.Item(index), C3MenuItem)
   End Get
   Set(ByVal value As C3MenuItem)
    MyBase.List.Item(index) = value
   End Set
  End Property

  Public Overridable Function Add(ByVal value As C3MenuItem) As 
Integer
   MyBase.List.Add(value)
  End Function

  Public Overloads Sub Remove(ByVal Index As Integer)

   ' ensure that the object exists in the collection.
   Dim mnuitm As C3MenuItem
   mnuitm = CType(Me.InnerList.Item(Index), C3MenuItem)

   ' remove object to the collection (by index).
   If Not mnuitm Is Nothing Then Me.InnerList.Remove(mnuitm)

  End Sub

 End Class

End Namespace


----------------------------------------------------------------------
------
-
C3MenuItem.vb - C3MenuItem Class Definition

Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Web.UI.WebControls.CommandEventArgs
Imports System.Drawing.Design
Imports System.Drawing
Imports System.Reflection
Imports System.Globalization
Imports System.ComponentModel
Imports System.ComponentModel.Design.Serialization

Namespace C3WebControls

 <DefaultProperty("Text"), _
  TypeConverter(GetType(C3MenuItem_TypeConverter)), _
  Description("Menu Item Properties Definition.")> _
  Public Class C3MenuItem

  <NonSerialized()> _
  Public pOwningMenu As C3Menu

  ' MenuItem property storage:
  Dim _align As String = ""
  Dim _closeonclick As Boolean = True
  Dim _color3dhigh As Color = ColorTranslator.FromHtml("")

... all properties are 1 of the above type - string, boolean, color.
... standard Property Get / Set ...

  Public Function Clone() As C3MenuItem

   Dim BinFormatter As New
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
   Dim memStream As New System.IO.MemoryStream

   ' Serialize the memorystream object to this instance of the object.
   BinFormatter.AssemblyFormat =
Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple
   BinFormatter.Serialize(memStream, Me)
   memStream.Position = 0

   ' DeSerialize the memorystream object.
   Dim newItm As New C3MenuItem
   newItm = CType(BinFormatter.Deserialize(memStream), C3MenuItem)

   ' return the clone.
   Return newItm

  End Function

 End Class


 Friend Class C3MenuItem_TypeConverter : Inherits TypeConverter

  Public Overloads Overrides Function CanConvertFrom(ByVal context As
ITypeDescriptorContext, ByVal sourceType As Type) As Boolean
   If sourceType Is GetType(InstanceDescriptor) Then
    Return True
   End If
   Return MyBase.CanConvertFrom(context, sourceType)
  End Function

  Public Overloads Overrides Function CanConvertTo(ByVal context As
ITypeDescriptorContext, ByVal destType As Type) As Boolean
   If destType Is GetType(InstanceDescriptor) Then
    Return True
   End If
   Return MyBase.CanConvertTo(context, destType)
  End Function

  Public Overloads Overrides Function ConvertTo(ByVal context As
ITypeDescriptorContext, ByVal culture As CultureInfo, ByVal value As 
Object,
ByVal destType As Type) As Object
   If destType Is GetType(InstanceDescriptor) Then
    Dim ci As ConstructorInfo =
GetType(C3MenuItem).GetConstructor(System.Type.EmptyTypes)
    Return New InstanceDescriptor(ci, Nothing, False)
   End If
   Return MyBase.ConvertTo(context, culture, value, destType)
  End Function

 End Class



----------------------------------------------------------------------
------
-
C3Menu_Designer.vb - C3Menu Designer Definition

Imports System.Web.UI.Design
Imports System.ComponentModel.Design
Imports System.ComponentModel
Imports System.Drawing.Design

Namespace C3WebControls

 ' Designer class for the C3Menu control.
 Public Class C3Menu_Designer : Inherits ControlDesigner

  ' Use PreFilterProperties to remove properties from the designer 
view.
  Protected Overloads Overrides Sub PreFilterProperties(ByVal 
Properties As
System.Collections.IDictionary)

   ' Invoke base class method:
   MyBase.PreFilterProperties(Properties)

   ' Remove specified properties from design view:
   Properties.Remove("AccessKey")
   Properties.Remove("Visible")

  End Sub

  ' Returns the html to use to represent an empty control at design 
time.
  Protected Overrides Function GetEmptyDesignTimeHtml() As String

   Dim sTxt As String = "No Menu Items Defined"
   Return CreatePlaceHolderDesignTimeHtml(sTxt)

  End Function

  ' Returns the html which represents the control at design time.
  Public Overrides Function GetDesignTimeHtml() As String

   ' Invoke base class method.
   Dim html As String = MyBase.GetDesignTimeHtml()

   ' Set reference to current control instance.
   Dim mnu As C3Menu = DirectCast(Component, C3Menu)

   Dim tblstyle As String
   tblstyle &= "width:" & mnu.Width.ToString & "; "
   tblstyle &= "height:" & mnu.Height.ToString & "; "

   ' If no items defined then display this.
   If mnu.MenuItems.Count = 0 Then Return html

   Dim itm As C3MenuItem
   Dim styl As C3MenuStyle
   Dim itmstyle As String

   ' set reference to menustyle object.
   styl = DirectCast(mnu.FindControl(mnu.MenuStyle), C3MenuStyle)

   ' if style was assigned, then use style font.
   If Not styl Is Nothing Then
    If Len(styl.FontFamily) > 0 Then tblstyle &= "font-family:" &
styl.FontFamily & "; "
    If Len(styl.FontSize) > 0 Then tblstyle &= "font-size:" & 
styl.FontSize
& "; "
    If Len(styl.FontWeight) > 0 Then tblstyle &= "font-weight:" &
styl.FontWeight & "; "
   End If

   ' Build a table for menu items.
   html = ""
   html &= "<table style=" & Chr(34) & tblstyle & Chr(34) & ">" & 
vbCrLf
   If LCase(mnu.Orientation) = "horizontal" Then html &= "<tr>"

   ' Display menu as defined.
   For Each itm In mnu.MenuItems

    If Not LCase(mnu.Orientation) = "horizontal" Then html &= "<tr>" &
vbCrLf

    html &= "<td>" & itm.Text & "</td>" & vbCrLf
    If Not LCase(mnu.Orientation) = "horizontal" Then html &= "</tr>" 
&
vbCrLf

   Next

   If LCase(mnu.Orientation) = "horizontal" Then html &= "</tr>"
   html &= "</table>"

   'System.Windows.Forms.MessageBox.Show("GetDesignTimeHtml - HTML:" &
vbCrLf & vbCrLf & html, "C3Menu_Designer")
   Return html

  End Function

 End Class

End Namespace


----------------------------------------------------------------------
------
-
WebForm1.aspx - WebForm HTML View

<cc1:C3Menu id="C3Menu1" style="LEFT: 208px; TOP: 120px" 
runat="server"
MenuStyle="C3MenuStyle1">
<MenuItems>
 <cc1:C3MenuItem Text="Item Text"></cc1:C3MenuItem>
 <cc1:C3MenuItem Text="Item Text"></cc1:C3MenuItem>
 <cc1:C3MenuItem Text="Item Text"></cc1:C3MenuItem>
 <cc1:C3MenuItem Text="Item Text"></cc1:C3MenuItem>
 <cc1:C3MenuItem Text="Last"></cc1:C3MenuItem>
</MenuItems>
</cc1:C3Menu>






 
Yahoo! Groups Links

<*> To visit your group on the web, go to:
     http://groups.yahoo.com/group/AspNetAnyQuestionIsOk/

<*> To unsubscribe from this group, send an email to:
     [EMAIL PROTECTED]

<*> Your use of Yahoo! Groups is subject to:
     http://docs.yahoo.com/info/terms/
 

Reply via email to