views:

364

answers:

2

I am currently converting what was a Console Application into a Windows Form application. Fortunatly i initially designed the application to work with a GUI in the future so there was not much code to change.

I have a UserCollection class which itself holds a List<> of type User/Member (Member is derives from User).

What i would like to do is to add each item in the UserCollection List<> to the ListView, so i can see each entry and have the multiple entries list vertically.

I have tried to implement this myself firstly by using:

        private void UpdatePeopleListings()
    {
        foreach (User person in newCollection)
        {
            listViewPeople.Items.Add(person.ToString());
        }
    }

Where newCollection is the new object created from the UserCollection class in the main windows form.

I recieve the error:

foreach statement cannot operate on variables of type 'Collection.UserCollection' because 'Collection.UserCollection' does not contain a public definition for 'GetEnumerator'

I then tried to make a small workaround, so in my UserCollection i created the following method:

        public User ReturnUser()
    {
        foreach (User person in _userCollection)
        {
            return person;
        }
        return null;
    }

(_userCollection is the List<> of Users/Members in UserCollection.cs)

And then use it like this:

private void UpdatePeopleListings()
    {
        listViewPeople.Items.Add(newCollection.ReturnUser().ToString());
    }

Although this does populate the ListView with an entry, it only populates the first entry. If i was to add more than one User/Member to the newCollection then it simply repeats the first entry.

How would i go about populating the ListView with ALL objects in the collection properly and how would i prevent it from repeating only one object.

UserCollecton.cs

///////////////////////////////////////////////////////////
//  UserCollection.cs
//  Implementation of the Class UserCollection
//  Generated by Enterprise Architect
//  Created on:      22-Oct-2009 22:40:30
///////////////////////////////////////////////////////////

#region Using Statements

using System;

using System.Collections.Generic;

using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

using System.IO;

#endregion

namespace Collection
{
    //Allows the class to be saved
    [Serializable()]

    public class UserCollection
    {
        #region Fields

        //Declares a list of type User (Which also holds derived Member objects)
        private List<User> _userCollection = new List<User>();


        //Holds number of members
        int nMember = 0;
        //Holds number of users
        int nUser = 0;

        #endregion

        #region Add Operations

        /// <summary>
        /// Adds a new user
        /// </summary>
        /// <param name="user"></param>
        public void AddUser(User user)
        {
            //Adds the user given in the operation parameters to the collection
            _userCollection.Add(user);
            nUser++;

            //Sorts the collection using the CompareTo() specified in the User class.
            _userCollection.Sort();

            //Console.WriteLine used for testing purposes
            //Console.WriteLine("added");
        }


        ///<summary>
        ///Adds a new Member
        ///</summary>
        /// <param name="member"></param>
        public void AddMember(Member member)
        {
            //Adds the member given in the operation parameters to the collection
            _userCollection.Add(member);
            nMember++;

            //Sorts the collection using the CompareTo() specified in the User class.
            _userCollection.Sort();

            //Console.WriteLine used for testing purposes
            //Console.WriteLine("added");
        }

        #endregion

        #region Removal Operations

        ///<summary>
        ///Removes a user based on FirstName,LastName and PostCode
        ///</summary> 
        /// <param name="person"></param>
        public void RemoveUser(User person)
        {
            //Only search collection for users if there is data in it
            if (_userCollection.Count > 0)
            {
                //Create a temp list for any matched found
                List<User> tempList = new List<User>();

                foreach (User u in _userCollection)
                {
                    //If the details stored in the collection match the details given in the search
                    if (u.FName == person.FName && u.LName == person.LName && u.PostCode == person.PostCode)
                    {
                        //Add any matches to the temp list
                        tempList.Add(u);
                    }
                    else
                    {
                        throw new ArgumentException("User not found");
                    }
                }

                //Delete any matches 
                foreach (User u in tempList)
                {
                    _userCollection.Remove(u);
                    //Decrement user count
                    nUser--;
                }
            }
            else
            {
                throw new AccessViolationException("No data in collection");
            }
        }

        /// <summary>
        /// Removes a user using Membership number
        /// </summary>
        /// <param name="number"></param>
        public void RemoveMember(int number)
        {
                //Create a temp list of type Member
                Member temp = new Member();

                //Use the temp list to compare types and store all objects of type member
                //found in the collection to it.
                List<User> Mems = _userCollection.FindAll(delegate(User u)
                { return u.GetType() == temp.GetType(); });

                //Delete any matches
                foreach (Member m in Mems)
                {
                    if (m.mNum == number)
                    {
                        _userCollection.Remove(m);
                        //Decrement member count
                        nMember--;
                    }
                    else
                    {
                        throw new ArgumentException("Member not found");
                    }
                }
        }

        #endregion

        #region Search Operations

        ///<summary>
        ///Returns member by Membership number
        /// </summary>
        /// 
        /// <param name="_mNumber"></param>
        public Member FindByMNo(int number)
        {
            //Create a temp list of type Member
            Member temp = new Member();

            //Use the temp list to compare types and store all objects of type member
            //found in the collection to it.
            List<User> Mems = _userCollection.FindAll(delegate(User u)
            { return u.GetType() == temp.GetType(); });

            //Return any matches found
            foreach (Member i in Mems)
            {
                if (i.mNum == number)
                {
                    return i;
                }
            }
            throw new ArgumentException("Member not found");
        }

        ///<summary>
        ///Returns a list of Users matching details given
        ///</summary>
        /// 
        /// <param name="_fName"></param>
        /// <param name="_lName"></param>
        public List<User> FindByName(User person)
        {
            //Create a temp list to store any matches
            List<User> temp = new List<User>();

            //Add matches found to the temp list
            foreach (User u in _userCollection)
            {
                if (u.LName == person.LName)
                {
                    temp.Add(u);
                }
            }

            if (temp.Count > 0)
            {
                //Return the list that holds any matches
                return temp;
            }

            throw new ArgumentException("User not found");
        }

        public User ReturnUser()
        {
            foreach (User person in _userCollection)
            {
                return person;
            }
            return null;
        }

        #endregion

        #region Edit Operations

        ///<summary>
        ///Edits a members membership expiry
        ///</summary>
        /// 
        /// <param name="member"></param>
        public void EditMemStatus(int member, DateTime newDate)
        {
                //Create a temp list of type Member
                Member temp = new Member();

                //Use the temp list to compare types and store all objects of type member
                //found in the collection to it.
                List<User> Mems = _userCollection.FindAll(delegate(User u)
                { return u.GetType() == temp.GetType(); });

                //Search for the member that matches the number given in the parameter
                foreach (Member m in Mems)
                {
                    if (m.mNum == member)
                    {
                        //Replace the match with the new expiry
                        m.mExp = newDate;
                    }
                    else
                    {
                        throw new ArgumentException("Date cannot be changed");
                    }
                }
        }

        #endregion

        #region I/O Operations

        public bool SaveData()
        {
            try
            {
                //Open the stream using the Data.txt file
                using (Stream stream = File.Open("Data.txt", FileMode.Create))
                {
                    //Create a new formatter
                    BinaryFormatter bin = new BinaryFormatter();
                    //Copy data in collection to the file specified earlier
                    bin.Serialize(stream, _userCollection);
                    bin.Serialize(stream, nMember);
                    bin.Serialize(stream, nUser);
                    //Close stream to release any resources used
                    stream.Close();
                }
                return true;
            }
            catch (IOException ex)
            {
                throw new ArgumentException(ex.ToString());
            }
        }

        public bool LoadData()
        {
            //Check if file exsists, otherwise skip
            if (File.Exists("Data.txt"))
            {
                try
                {
                    using (Stream stream = File.Open("Data.txt", FileMode.Open))
                    {
                        BinaryFormatter bin = new BinaryFormatter();

                        //Copy data back into collection fields
                        _userCollection = (List<User>)bin.Deserialize(stream);
                        nMember = (int)bin.Deserialize(stream);
                        nUser = (int)bin.Deserialize(stream);
                        stream.Close();

                        //Sort data to ensure it is ordered correctly after being loaded
                        _userCollection.Sort();
                        return true;

                    }
                }
                catch (IOException ex)
                {
                    throw new ArgumentException(ex.ToString());
                }
            }
            else
            {
                //Console.WriteLine present for testing purposes
                Console.WriteLine("\nLoad failed, Data.txt not found");
                return false;
            }
        }

        #endregion

        #region Properties

        //Gets amount of Members in collection
        public int GetNMember
        {
            get
            {
                return nMember;
            }
        }

        //Gets amount of Users in collectioj
        public int GetNUser
        {
            get
            {
                return nUser;
            }
        }

        #endregion

    }//end UserCollection
}

Ignore any random Console stuff, i've not finished the cleanup yet.

Thanks for the help!

+2  A: 

The foreach doesn't work because your UserCollection class doesn't implement the IEnumerable interface.

The ListItems is not what you expected, because you do not understand how the ListView / ListViewItems work. A ListView consists of ListViewItems, and a ListViewItem can consists of SubItems (which are only displayed when the ListView's viewstyle is set to 'report').

When you add a ListViewItem using the method that you're using, only the 'caption' of the ListViewItem is defined. This means, that you'll have to use another overload of the Add method; the method which takes a ListViewItem object as an argument. Then, you can do this:

ListViewItem item = new ListViewItem();
item.Text = "bar";
item.SubItems.Add ("foo");
item.SubItems.Add ("foo2");
myListView.Items.Add (item);

On the question that only one item is added to your list: - you are only adding one item ... More specifically, you're adding the collection itself, rather then creating a ListViewItem for each object that is in your collection.

So what you have to do is:

  • iterate over your list (using foreach (means you have to implement IEnumerable on the collection class), or using a for loop (but you'll have to make sure that you can access the contents of the collection using an indexer for instance))
  • create a ListViewItem for each object that exists in the list.

I wonder why you've created your custom UserCollection in the first place though. I see that you've implemented some specific functionality, but .... I think there are better solutions. Nonetheless, you should implement the IEnumerable interface, the IList interface, etc... for that class. By doing so, your class will be a 'real collection', and then you can work with it like any other collection class. (Iterate using foreach, or using a for loop, etc..)

Frederik Gheysels
+1 to all of the above, and one more thing: consider using `DataGridView` over `ListView`. `DataGridView` can be directly bound to collections, with no need to create and then synchronize items.
Pavel Minaev
Works fine, initially had some problems where not all the data would not show. I had to manually code the following properties to get all items and columns to show up: listViewPeople.View = View.Details; listViewPeople.FullRowSelect = true; listViewPeople.GridLines = true;Also, is there a way so that the list is not repopulated with all the entries whenever i add a new one. I have to call listViewPeople.Items.Clear(); before i add all items to ensure that no data is repeated.
Jamie Keeling
+1  A: 

In conjunction with Frederik Gheysel's answer, it would be wise to implement IEnumerator also. Remember to override Equals, GetHashCode and ToString when doing so.

Hope this helps, Best regards, Tom.

tommieb75
Great suggestion =]
Jamie Keeling