Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / Windows Forms / WinForm General / September 2004

Tip: Looking for answers? Try searching our database.

Adding to custom collection property in designer

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Bob Dankert - 21 Sep 2004 18:31 GMT
I have a custom control (inheriting from ListBox) which has a collection as
a property.  This collection implements IList (and ICollection, IEnumerator)
and has the DesignerSerializationVisibility set to Content.  The collection
consists of a custom class I created, which I also created a typeconverter
so I can use the Visual Studio designer to add items to my collection.  When
I try to add items to my collection, I get an error that the constructor can
not be found.

I tried to use this code without the typeconverter and I had the problem
when I added items to my collection, the code would not be created by
designer in VS and therefore they would never be added.

I would appreciate any suggestions

My code for the collection property of the control is here:

[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public MyControls.MyListBoxColumnCollection Columns
{
get
{
return this.columns;
}
set
{
this.columns = value;
}
}

The code for the Column item is here (I am omiting the code for the
columncollection as this is very basic):

using System;
using System.Globalization;
using System.ComponentModel;
using System.ComponentModel.Design.Serialization;
using System.Reflection;
namespace MyControls
{
/// <summary>
/// Summary description for MyListBoxColumn.
/// </summary>
[TypeConverter(typeof(MyListBoxColumnConverter))]
public class MyListBoxColumn
{
private int width;
public MyListBoxColumn(int width)
{
this.width = width;
}
public int Width
{
get
{
return this.width;
}
set
{
this.width = value;
}
}
}
internal class MyListBoxColumnConverter : TypeConverter
{
public override bool CanConvertTo(ITypeDescriptorContext context,Type
destinationType)
{
if (destinationType == typeof(InstanceDescriptor))
{
return true;
}
return base.CanConvertTo(context, destinationType);
}
public override object ConvertTo(ITypeDescriptorContext context,CultureInfo
culture, object value, Type destinationType)
{
if (destinationType == typeof(InstanceDescriptor))
{
MyListBoxColumn col = (MyListBoxColumn)value;
//DockPosition dp = (DockPosition)value;
ConstructorInfo ctor = typeof(MyListBoxColumn).GetConstructor(new Type[]
{typeof(int)});
//ConstructorInfo ctor = typeof(DockPosition).GetConstructor(new Type[]
{typeof(int), typeof(int)});
return new InstanceDescriptor(ctor, new object[] {col.Width});
//return new InstanceDescriptor(ctor, new object[] {dp.Left,dp.Top});
}
return ConvertTo(context, culture, value, destinationType);
}
}
}

Thanks

Bob Dankert
Claes Bergefall - 22 Sep 2004 08:05 GMT
The collection editor calls the public empty constructor
when you press the Add button. Since you don't have
such a constructor you'll get an error. That gives you
two options:

1. Provide a public empty constructor
2. Inherit CollectionEditor and override the
CreateInstance method. Add the Editor
attribute to your collection property
(i.e. Columns) to use your inherited editor

I noticed that the collection property (i.e. Columns)
is read-write. Are you sure you want that (usually
such properties are read-only)?

   /claes

> I have a custom control (inheriting from ListBox) which has a collection as
> a property.  This collection implements IList (and ICollection, IEnumerator)
[quoted text clipped - 91 lines]
>
> Bob Dankert
Bob Dankert - 22 Sep 2004 15:26 GMT
I made the suggested change to provide an empty parameterless constructor,
and now when I try to add a column I get an unhandles
System.StackOverflowException and Visual Studio immediately terminates.

Any other ideas?

Bob

> The collection editor calls the public empty constructor
> when you press the Add button. Since you don't have
[quoted text clipped - 115 lines]
>>
>> Bob Dankert
Claes Bergefall - 23 Sep 2004 07:23 GMT
That should work. What does your new constructor look like?
Could you post the rest of the (relevant) code?

   /claes

> I made the suggested change to provide an empty parameterless constructor,
> and now when I try to add a column I get an unhandles
[quoted text clipped - 42 lines]
> >>
> >> My code for the collection property of the control is here:

[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
> >> public MyControls.MyListBoxColumnCollection Columns
> >> {
[quoted text clipped - 75 lines]
> >>
> >> Bob Dankert
"Jeffrey Tan[MSFT]" - 23 Sep 2004 09:29 GMT
Hi Bob,

Based on my understanding, you want to add custom design-time editor for
Collection property.

I have writen a sample project, which works well:
public class UserControl1 : System.Windows.Forms.UserControl
{
    [TypeConverter(typeof(MyListBoxColumnConverter))]
    public class MyListBoxColumn
    {
        public MyListBoxColumn()
        {
        }

        private int width=0;
        public MyListBoxColumn(int width)
        {
            this.width = width;
        }

        public int Width
        {
            get
            {
                return this.width;
            }
            set
            {
                this.width = value;
            }
        }
    }

    public class MyListBoxColumnConverter : TypeConverter
    {
        public override bool CanConvertTo(ITypeDescriptorContext context,Type
destinationType)
        {
            if (destinationType == typeof(InstanceDescriptor))
            {
                return true;
            }
            if(destinationType==typeof(string))
            {
                return true;
            }
            return base.CanConvertTo(context, destinationType);
        }

        public override object ConvertTo(ITypeDescriptorContext context,
System.Globalization.CultureInfo culture, object value, Type
destinationType)
        {
            MyListBoxColumn col = (MyListBoxColumn)value;
            if (destinationType == typeof(InstanceDescriptor))
            {
                //DockPosition dp = (DockPosition)value;
                ConstructorInfo ctor = typeof(MyListBoxColumn).GetConstructor(new
Type[] {});
                //ConstructorInfo ctor = typeof(DockPosition).GetConstructor(new Type[]
{typeof(int), typeof(int)});
                return new InstanceDescriptor(ctor, null);
                //return new InstanceDescriptor(ctor, new object[] {dp.Left,dp.Top});
            }
            if(destinationType==typeof(string))
            {
               return "MyListBoxColumn"+col.Width.ToString();
            }
            return base.ConvertTo(context, culture, value, destinationType);
        }
    }

    MyListBoxColumnCollection columns=null;

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    public MyListBoxColumnCollection  Columns
    {
        get
        {
            if(columns==null)
            {
                columns=new MyListBoxColumnCollection();
            }
            return this.columns;
        }
        set
        {
            this.columns = value;
        }
    }

      [TypeConverter(typeof(MyListBoxColumnCollectionConverter))]
    public class MyListBoxColumnCollection: CollectionBase
    {
        public MyListBoxColumn this[int index]
        {
            get
            {
                return List[index] as MyListBoxColumn;
            }
        }

        public void Add(MyListBoxColumn item)
        {
            List.Add(item);
        }

        public void AddRange(MyListBoxColumn[] items)
        {
            foreach(MyListBoxColumn item in items)
            {
                List.Add(item);
            }
        }
    }

    internal class MyListBoxColumnCollectionConverter : TypeConverter
    {
        public override bool CanConvertTo(ITypeDescriptorContext context,Type
destinationType)
        {
            if (destinationType == typeof(string))
            {
                return true;
            }
            return base.CanConvertTo(context, destinationType);
        }

        public override bool CanConvertFrom(ITypeDescriptorContext context, Type
sourceType)
        {
            if(sourceType==typeof(string))
            {
                return true;
            }
            return base.CanConvertFrom (context, sourceType);
        }

        public override object ConvertFrom(ITypeDescriptorContext context,
System.Globalization.CultureInfo culture, object value)
        {
            if(value is string)
            {
                string str=(string)value;
                string[] str_arr=str.Split(new char[]{','});

                MyListBoxColumnCollection collection=new MyListBoxColumnCollection();
                foreach(string item in str_arr)
                {
                    MyListBoxColumn mlbc=new MyListBoxColumn(int.Parse(item));
                    collection.Add(mlbc);
                }
                return collection;
            }
            return base.ConvertFrom (context, culture, value);
        }

        public override object ConvertTo(ITypeDescriptorContext context,
System.Globalization.CultureInfo culture, object value, Type
destinationType)
        {
            if (destinationType == typeof(string))
            {
                MyListBoxColumnCollection collection = (MyListBoxColumnCollection)value;
                string str=string.Empty;
                foreach(MyListBoxColumn mlbc in collection)
                {
                    str=str+mlbc.Width.ToString()+",";
                }
                str=str.Substring(0, str.Length-1);
                return str;
            }
            return base.ConvertTo(context, culture, value, destinationType);
        }
    }
}
==============================================================
Thank you for your patience and cooperation. If you have any questions or
concerns, please feel free to post it in the group. I am standing by to be
of assistance.

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Signature

Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.

Bob Dankert - 24 Sep 2004 14:27 GMT
Jeffrey,

After doing more testing with this code you provided (the UserControl1
class), I found that while it does add the columns, I have a couple
difficulties:

1.  It does not save the widths I assign to the columns.  They all go back
to 0 eventually.

2.  Instead of showing (Collection) ...  in the properties of the designer,
it shows the values of the widths.  This works fine, but would be nice to
have it work like the rest of the collections.

3.  Is there a way to have the columns automatically name themselves, such
as myListBoxColumn1, myListBoxColumn2, myListBoxColumn3, etc...?

Thanks a ton for all your help,

Bob Dankert
> Hi Bob,
>
[quoted text clipped - 183 lines]
> Get Secure! - www.microsoft.com/security
> This posting is provided "as is" with no warranties and confers no rights.
"Jeffrey Tan[MSFT]" - 24 Sep 2004 08:02 GMT
Hi Bob,

Also, we may explicitly specify the CollectionEditor to use certain
constructor through inherit the default CollectionEditor, then override
CollectionEditor.CreateInstance method and explicitly call the constructor.
Like this:
public class MyCollectionEditor: CollectionEditor
{
      private Type[] types;
    public MyCollectionEditor(Type type): base(type)
    {
        types=new Type[]{typeof(MyListBoxColumn)};
    }
   
    protected override Type[] CreateNewItemTypes()
    {
        return types;
    }

    protected override object CreateInstance(Type itemType)
    {
        if(itemType==typeof(MyListBoxColumn))
        {
            MyListBoxColumn mlbc=new MyListBoxColumn(1);
            return mlbc;
        }
        return base.CreateInstance(itemType);
    }
}

Thank you for your patience and cooperation. If you have any questions or
concerns, please feel free to post it in the group. I am standing by to be
of assistance.

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Signature

Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.

Bob Dankert - 24 Sep 2004 14:15 GMT
Thanks a lot for all your help.  I played around with your stuff and
switched around some of my code with yours and was able to determine that my
collection is the problem.  If I use all of your code except substitute my
collection in for yours, then the code will no longer work -- it does not
save columns when I add them with the column editor.

I will paste my code below as I am curious what might be wrong with this?

public class MyListBoxColumnCollection : IList
{
private ArrayList myList;
public MyListBoxColumnCollection()
{
myList = new ArrayList();
}
public virtual void AddRange(MyListBoxColumn[] values)
{
foreach (MyListBoxColumn ch in values)
this.myList.Add(ch);
}
#region IList Explicait Members
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public MyListBoxColumn this[int index]
{
get
{
if (index > this.myList.Count-1)
{
throw new ArgumentOutOfRangeException("MyListBoxColumnCollection.Items
index",index,"Index out of range, please specify a valid value");
}
else
return (MyListBoxColumn)this.myList[index];
}
set
{
if (index > this.myList.Count-1)
{
throw new ArgumentOutOfRangeException("MyListBoxColumnCollection.Items
index",index,"Index out of range, please specify a valid value");
}
else
this.myList[index] = value;
}
}
public void Insert(int index, MyListBoxColumn value)
{
if (index > this.myList.Count-1)
{
throw new ArgumentOutOfRangeException("MyListBoxColumnCollection.Items
index",index,"Index out of range, please specify a valid value");
}
this.myList.Insert(index, value);
}
public void Remove(MyListBoxColumn value)
{
if (this.myList.Contains(value))
this.myList.Remove(value);
}
public bool Contains(MyListBoxColumn value)
{
return this.myList.Contains(value);
}
public int IndexOf(MyListBoxColumn value)
{
return this.myList.IndexOf(value);
}
public int Add(MyListBoxColumn value)
{
return this.myList.Add(value);
}
#endregion
#region ICollection Members
public bool IsSynchronized
{
get
{
return this.myList.IsSynchronized;
}
}
public int Count
{
get
{
return this.myList.Count;
}
}
public void CopyTo(Array array, int index)
{
this.myList.CopyTo(array, index);
}
public object SyncRoot
{
get
{
return this.myList.SyncRoot;
}
}
#endregion
#region IEnumerable Members
public IEnumerator GetEnumerator()
{
return this.myList.GetEnumerator();
}
#endregion
#region IList Members
public bool IsReadOnly
{
get
{
return false;
}
}
object System.Collections.IList.this[int index]
{
get
{
return null;
}
set
{
}
}
void System.Collections.IList.Insert(int index, object value)
{
}
void System.Collections.IList.Remove(object value)
{
}
bool System.Collections.IList.Contains(object value)
{
return false;
}
int System.Collections.IList.IndexOf(object value)
{
return 0;
}
int System.Collections.IList.Add(object value)
{
return 0;
}
public void Clear()
{
this.myList.Clear();
}
public void RemoveAt(int index)
{
if (index > this.myList.Count-1)
{
throw new ArgumentOutOfRangeException("MyListBoxColumnCollection.Items
index",index,"Index out of range, please specify a valid value");
}
this.myList.RemoveAt(index);
}
public bool IsFixedSize
{
get
{
return false;
}
}

#endregion
}

Thanks a ton,

Bob Dankert

> Hi Bob,
>
[quoted text clipped - 36 lines]
> Get Secure! - www.microsoft.com/security
> This posting is provided "as is" with no warranties and confers no rights.
Bob Dankert - 24 Sep 2004 15:04 GMT
Ok, I'm sorry for all of the erradic replies, but here is another problem I
ran into.  When I try to work with the CollectionEditor, I keep getting an
error that it doesnt belong in the System.ComponentModem.Design namespace.

C:\Programming\Projects\lbcoltest\lbcoltest\lbedit.cs(9): The type or
namespace name 'CollectionEditor' does not exist in the class or namespace
'System.ComponentModel.Design' (are you missing an assembly reference?)

I'm not really sure what is causing this?

Bob Dankert
> Hi Bob,
>
[quoted text clipped - 36 lines]
> Get Secure! - www.microsoft.com/security
> This posting is provided "as is" with no warranties and confers no rights.
"Jeffrey Tan[MSFT]" - 27 Sep 2004 10:18 GMT
Hi Bob,

This is because System.ComponentModel.Design.CollectionEditor is not
included in default assembly in VS.NET IDE, we should add System.Design.dll
into application as reference. Then we should have no problem using this
class.

Best regards,
Jeffrey Tan
Microsoft Online Partner Support
Signature

Get Secure! - www.microsoft.com/security
This posting is provided "as is" with no warranties and confers no rights.

Bob Dankert - 27 Sep 2004 14:38 GMT
Jeffrey,

I noticed this over the weekend, unfortunately I was getting rather
frusterated with other stuff and not thinking very logically.

Bob Dankert

> Hi Bob,
>
[quoted text clipped - 9 lines]
> Get Secure! - www.microsoft.com/security
> This posting is provided "as is" with no warranties and confers no rights.

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.