views:

470

answers:

3

One example is described here. But the author apparently forgot to include the code for download.

Another example is shown here. However, this one doesn't quite work (as described in comments).

How do you do this correctly?

+4  A: 

The second example you found almost works, it's just missing a little bit. All that was needed was 2 methods in the main control.

Add this code to the AppointmentControl.cs file and it will work.

protected override object SaveViewState()
{
    if (appointments != null)
        return appointments.SaveViewState();
    return null;
}

protected override void LoadViewState(object savedState)
{
    appointments = new AppointmentCollection();
    appointments.LoadViewState(savedState);
}

The code in the example site was pretty decent. It implemented all of the interfaces it should have and did a pretty good job. Where it fell apart was that, despite having all of the code it needed in the abstract bits, that didn't matter because the interfaces weren't referenced in the places they needed to be.

The collection classes being used had nothing "special" about them, other than implementing a few interfaces. The framework won't automatically call these methods. The framework will however call the overridden methods I wrote above, which you need to implement in order for your control to save the elements in the collection. As long as you call them, everything will work.

Dan Herbert
+3  A: 

DanHerbert got it. Darn, I spent hours on this too! In the process of trying to answer this question I came up with a simplified generic StateManagedCollection that inherits from the framework's built-in StateManagedCollection, based on the version here. Maybe you'll find it useful. Full source code of my sample project available here.

using System;
using System.Collections;
using System.Collections.Specialized;
using System.Security.Permissions;
using System.Web;
using System.Collections.Generic;
using System.Web.UI;

namespace Web
{
    public abstract class StateManagedCollection<T> : StateManagedCollection, IList<T>, ICollection<T>, IEnumerable<T>
        where T : class, IStateManagedItem, new()
    {

        protected override object CreateKnownType(int index)
        {
            return Activator.CreateInstance<T>();
        }

        protected override Type[] GetKnownTypes()
        {
            return new Type[] { typeof(T) };
        }

        protected override void SetDirtyObject(object o)
        {
            ((IStateManagedItem)o).SetDirty();
        }

        #region IList<T> Members

        public int IndexOf(T item)
        {
            return ((IList)this).IndexOf(item);
        }

        public void Insert(int index, T item)
        {
            ((IList)this).Insert(index, item);
            if (((IStateManager)this).IsTrackingViewState)
            {
                this.SetDirty();
            }
        }

        public void RemoveAt(int index)
        {
            ((IList)this).RemoveAt(index);
            if (((IStateManager)this).IsTrackingViewState)
            {
                this.SetDirty();
            }
        }

        public T this[int index]
        {
            get { return (T)this[index]; }
            set { this[index] = value; }
        }

        #endregion

        #region ICollection<T> Members

        public void Add(T item)
        {
            ((IList)this).Add(item);
            this.SetDirty();
        }

        public bool Contains(T item)
        {
            return ((IList)this).Contains(item);
        }

        public void CopyTo(T[] array, int arrayIndex)
        {
            ((IList)this).CopyTo(array, arrayIndex);
        }

        public bool IsReadOnly
        {
            get { return false; }
        }

        public bool Remove(T item)
        {
            if (((IList)this).Contains(item))
            {
                ((IList)this).Remove(item);
                return true;
            }
            return false;
        }

        #endregion


        #region IEnumerable<T> Members

        IEnumerator<T> IEnumerable<T>.GetEnumerator()
        {
            throw new NotImplementedException();
        }

        #endregion

        #region IEnumerable Members

        IEnumerator IEnumerable.GetEnumerator()
        {
            return ((IList)this).GetEnumerator();

        }

        #endregion
    }
}
davogones
Tough choice for bounty award, but the full source code is super helpful. Thanks.
Larsenal
You're not implementing IEnumerable<T>.GetEnumerator(). If you're using .NET 3.5, you can replace that throw with the following:((IEnumerable<T>)this).Cast<T>().GetEnumerator();
Dave Van den Eynde
A: 

Hello guys,

I have used the code above the provided solution is ok but i was getting exception - "StackOverflow " cool :) the issue is reproducible by adding a few child items in the aspx page and switch to Design view to design view of Visual studio ( Visual Studio just restart and nobody knows what is going on....).

    IEnumerator IEnumerable.GetEnumerator()
    {
        return ((IList)this).GetEnumerator();

    }

So, I guess I figured it out just change the implementation of the above method like this:

    IEnumerator IEnumerable.GetEnumerator()
    {
        // return ((IList)this).GetEnumerator();
        return this.GetEnumerator();

    } 

Hope this will help someone else like me :) just not to loose few hours to get it work with the designer of VS

Rado