Click here to Skip to main content
15,891,529 members
Please Sign up or sign in to vote.
3.00/5 (1 vote)
See more:
I am working on a project (simple phone book) for personal use. Basically, the contacts are displayed in a listview and stored in a XML file. I am having trouble deleting the last remaining item in my listview (listView1).

This is how my XML looks like:

<People>
  <Person>
    <Name>John</Name>
    <Hometown>Washington</Hometown>
    <Address>231 Main Street</Address>
    <Birthday>130299511993682082</Birthday>
    <Phone>555-555-555</Phone>
    <Email>john@gmail.com</Email>
    <AdditionalInfo>Skype: john.123</AdditionalInfo>
  </Person>
  <Person>
    <Name>123</Name>
    <Hometown>
    </Hometown>
    <Address>
    </Address>
    <Birthday>130299621669230698</Birthday>
    <Phone>
    </Phone>
    <Email>
    </Email>
    <AdditionalInfo>
    </AdditionalInfo>
  </Person>
</People>


So, let's say that I have got 5 contacts in the list and when I try to remove all of them, it's not possible. It is possible to remove only 4 of them. When I try to remove all of them and then close/run the application, there will be no removed contacts - all of them will still be there, like I haven't removed them at all. When I try to remove 4 of them and I close/run the program, they would be deleted. When I try to remove the last one, it is not possible either - when I close/run app it would always remain there.

Also, sometimes there is an error as well, when I try to just select some of the contacts - usually after already deleting them. So, just to make things clear, let's say that I have got 10 contacts and remove 5 of them, when I try to select the sixth contact - the error shows:

IMAGE

I think maybe this part of the code is bugged:

C#
private void listView1_SelectedIndexChanged(object sender, System.EventArgs e)
        {
            if (listView1.SelectedItems.Count == 0)
            {
                toolStripEdit.Enabled = false;
                RefreshAll();
                return;
            }
            Person person = new Person();
            person = FindPerson(listView1.SelectedItems[0].Text);
            txt_Name.Text = person.Name;
            txt_City.Text = person.Hometown;
            txt_Address.Text = person.Address;
            txt_Phone.Text = person.Phone;
            txt_Mail.Text = person.Email;
            txt_MoreInfo.Text = person.AdditionalInfo;
            dateTimePicker1.Value = person.Birthday;
            ReadOnlyON();
            toolStripEdit.Enabled = true;
            ExpandThis();
        }


and this one as well:

void Rmv()
        {
            if (Properties.Settings.Default.Remove == true)
            {
                DialogResult dialogResult = MessageBox.Show("Are you sure you want to delete this contact?", "Confirm", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                if (dialogResult == DialogResult.Yes)
                {
                    Remove();
                    if (Properties.Settings.Default.Sync == true) { Sync(); }
                }
                else if (dialogResult == DialogResult.No)
                {
                    return;
                }
            }
            else
            {
                Remove();
                if (Properties.Settings.Default.Sync == true) { Sync(); }
            }
        }
        void Remove()
        {
            Person person = new Person();
            person = FindPerson(listView1.SelectedItems[0].Text);
            if (listView1.SelectedItems.Count > 0)
            {
                try
                {
                    if (listView1.SelectedItems.Count == 0) return;
                    people.RemoveAt(listView1.SelectedItems[0].Index);
                    foreach (ListViewItem eachItem in listView1.SelectedItems)
                    {
                        listView1.Items.Remove(eachItem);
                    }
                }
                catch { }
                ClearAll();
                ReadOnlyON();
            }
            else
            {
                MessageBox.Show("Nothing is selected!", "Notification", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            ReadOnlyOFF();
            UserCount();
            if (Properties.Settings.Default.Sync == true) { Sync(); }
        }


Since it doesn't makes sense to upload the whole code here, I have uploaded it here if someone wants to help and take a closer look at it.

Thanks in advance.

How can I solve this issue?

@EDIT:

This is the connection between listview and XML:

private void Main_Load(object sender, EventArgs e)
        {
            LoadContacts();
        }

void LoadContacts()
        {
            string path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
            string phonebook_path = path + "\\Phonebook\\Contacts.xml";
            if (!File.Exists(phonebook_path))
            {
                XmlTextWriter xW = new XmlTextWriter(phonebook_path, Encoding.UTF8);
                xW.WriteStartElement("People");
                xW.WriteEndElement();
                xW.Close();
            }
            XmlDocument xDoc = new XmlDocument();
            xDoc.Load(phonebook_path);
            foreach (XmlNode xNode in xDoc.SelectNodes("People/Person"))
            {
                Person p = new Person();
                p.Name = xNode.SelectSingleNode("Name").InnerText;
                p.Hometown = xNode.SelectSingleNode("Hometown").InnerText;
                p.Address = xNode.SelectSingleNode("Address").InnerText;
                p.Birthday = DateTime.FromFileTime(Convert.ToInt64(xNode.SelectSingleNode("Birthday").InnerText));
                p.Phone = xNode.SelectSingleNode("Phone").InnerText;
                p.Email = xNode.SelectSingleNode("Email").InnerText;
                p.AdditionalInfo = xNode.SelectSingleNode("AdditionalInfo").InnerText;
                people.Add(p);
                listView1.Items.Add(p.Name);
                UserCount();
            }
        }

private void Main_FormClosing(object sender, FormClosingEventArgs e)
        {
            XmlDocument xDoc = new XmlDocument();
            string path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
            string phonebook_path = path + "\\Phonebook\\Contacts.xml";
            xDoc.Load(phonebook_path);
            XmlNode xNode = xDoc.SelectSingleNode("People");
            xNode.RemoveAll();
            foreach (Person p in people)
            {
                XmlNode xTop = xDoc.CreateElement("Person");
                XmlNode xName = xDoc.CreateElement("Name");
                XmlNode xHometown = xDoc.CreateElement("Hometown");
                XmlNode xAddress = xDoc.CreateElement("Address");
                XmlNode xBirthday = xDoc.CreateElement("Birthday");
                XmlNode xPhone = xDoc.CreateElement("Phone");
                XmlNode xEmail = xDoc.CreateElement("Email");
                XmlNode xAdditionalInfo = xDoc.CreateElement("AdditionalInfo");
                xName.InnerText = p.Name;
                xHometown.InnerText = p.Hometown;
                xAddress.InnerText = p.Address;
                xBirthday.InnerText = p.Birthday.ToFileTime().ToString();
                xPhone.InnerText = p.Phone;
                xEmail.InnerText = p.Email;
                xAdditionalInfo.InnerText = p.AdditionalInfo;
                xTop.AppendChild(xName);
                xTop.AppendChild(xHometown);
                xTop.AppendChild(xAddress);
                xTop.AppendChild(xBirthday);
                xTop.AppendChild(xPhone);
                xTop.AppendChild(xEmail);
                xTop.AppendChild(xAdditionalInfo);
                xDoc.DocumentElement.AppendChild(xTop);
                xDoc.Save(phonebook_path);
            }
        }
Posted
Updated 27-Nov-13 14:24pm
v2
Comments
BillWoodruff 27-Nov-13 19:43pm    
Are you saying that the code that removes selected items from the ListView has a distinct problem: one unrelated to the problem of removing entries from your XML file ?

Is there any dependency ... any binding ... between your XML source and the ListView ?

Just eyeballing your code, I see no problem with removing any or all items selected from the ListViewItem.
Exinta Ennea 27-Nov-13 20:19pm    
I apologise, I thought I presented my problem clearly enough.

Techically, removing from listview works fine, but the result at the end is not what I was looking for (I want contact to be removed from listview and the XML file as well - because this is the only proper way of removing the contact). So my guess is that the problem is removing from XML. Please note that I am quite new to c# and this is only my guess.

Please, check my question again I have added some more details which I thought you were asking me about. The problem is certainly there - I have posted the picture showing the exact error.

I think you are coming to the problem with a wrong side, trying to mix UI, XML and data. You need to deal with these three parts separately. First of all, you don't have to deal with XML directly. You can use Data Contract which takes care of this part. You simply have your data model (one or several data classes), and any arbitrary object graph will be stored for you in any stream to be later restored the way it was, with all its references put under the contract. Please see:
http://msdn.microsoft.com/en-us/library/ms733127.aspx[^].

For more detail, please see my past answers:
How can I utilize XML File streamwriter and reader in my form application?[^],
Creating property files...[^].

Also, separate the UI. The UI part should be data aware, but data model should not be aware of UI. UI should be able to populate control out of data model, and updates in UI should refresh the data model. The serializer should work only with data model and be totally agnostic to UI.

See also: http://en.wikipedia.org/wiki/Separation_of_concerns[^].

It looks like you scenario is simple enough, so the just my simple considerations could be enough. To go deeper, you can consider learning architectural patterns mentioned in my past answer: How to populate a CList with values from dialog controls?[^].

—SA
 
Share this answer
 
v3
Comments
Exinta Ennea 27-Nov-13 17:27pm    
Thanks for your answer my Russian bro.

Nevertheless, I am really trying hard to understand what did you exactly mean, but having no success in doing so since I am quite new to c#. Please note that I have taken a look at your links, but as I said, since im a beginner it seems like science fiction to me.

Could you anyhow make the answer more understandable to me?

Thanks once again.
Sergey Alexandrovich Kryukov 27-Nov-13 18:34pm    
More understandable? Hm... The process can only be mutual. If you can point out what exactly you need to clarify first...

But look, you cannot replace learning with something simpler. You see, if you do all the data manipulation "manually" (more exactly, in lower-level ad-hoc technique), with the excuse of lack of understanding of "science fiction" facilities written for you to make you work more robust, reliable for much less time, you would spend much more time with much less reliable results.

Data Contract based technologies internally are really of some top-notch sophistication. I know that because I'm the author of such technology myself. It is based on emitting of the code on the fly, using System.Reflection.Emit, which requires good knowledge of IL language and hard to debug. But on the usage level, the situation is just the opposite: your objects are saved in stream and restored back, you don't have to concern about the procedures giving you this effect. And then, you can practically forget about XML and files. Everything is done for you, in data-agnostic manner. To start with, try to read the referenced articles again, until you see a first sample showing [DataContract] attribute in sample code. Nothing can be easier...

—SA
phil.o 30-Nov-13 5:46am    
Upvoted your answer as it really makes sense.
Don't know why it had been downvoted.
Sergey Alexandrovich Kryukov 30-Nov-13 18:41pm    
Thank you very much. Such down-votes happen all the time, no need to pay much attention...
—SA
Here's the modified code to the Phonebook. No science fiction included.

C#
void Remove()
{
Person person = new Person();
try { person = FindPerson(listView1.SelectedItems[0].Text); } catch { return; }
if (listView1.SelectedItems.Count > 0)
{
try
{
if (listView1.SelectedItems.Count == 0) return;
foreach (ListViewItem eachItem in listView1.SelectedItems)
{
people.RemoveAll(x => x.Name == eachItem.Text);
listView1.Items[listView1.Items.Count - 1].Selected = true;
listView1.Items.Remove(eachItem);
}
}
catch { }
ClearAll();
ReadOnlyON();
}
else
{
MessageBox.Show("Nothing is selected!", "Notification", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
ReadOnlyOFF();
UserCount();
Sync();
}

C#
private void listView1_SelectedIndexChanged(object sender, System.EventArgs e)
    {
if (listView1.SelectedItems.Count == 0)
{
toolStripEdit.Enabled = false;
RefreshAll();
return;
}

try {
Person person = new Person();
person = people[people.FindIndex(0, x => x.Name == listView1.SelectedItems[0].Text && x.Name != null)];
txt_Name.Text = person.Name;
txt_City.Text = person.Hometown;
txt_Address.Text = person.Address;
txt_Phone.Text = person.Phone;
txt_Mail.Text = person.Email;
txt_MoreInfo.Text = person.AdditionalInfo;
dateTimePicker1.Value = person.Birthday;
ReadOnlyON();
toolStripEdit.Enabled = true;
ExpandThis();
} catch (Exception ex) {
return;
}
}

C#
private void Main_FormClosing(object sender, FormClosingEventArgs e)
{
XmlDocument xDoc = new XmlDocument();
string path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string phonebook_path = path + "\\Phonebook\\Contacts.xml";
xDoc.Load(phonebook_path);
XmlNode xNode = xDoc.SelectSingleNode("People");
xNode.RemoveAll();
foreach (Person p in people)
{
XmlNode xTop = xDoc.CreateElement("Person");
XmlNode xName = xDoc.CreateElement("Name");
XmlNode xHometown = xDoc.CreateElement("Hometown");
XmlNode xAddress = xDoc.CreateElement("Address");
XmlNode xBirthday = xDoc.CreateElement("Birthday");
XmlNode xPhone = xDoc.CreateElement("Phone");
XmlNode xEmail = xDoc.CreateElement("Email");
XmlNode xAdditionalInfo = xDoc.CreateElement("AdditionalInfo");
xName.InnerText = p.Name;
xHometown.InnerText = p.Hometown;
xAddress.InnerText = p.Address;
xBirthday.InnerText = p.Birthday.ToFileTime().ToString();
xPhone.InnerText = p.Phone;
xEmail.InnerText = p.Email;
xAdditionalInfo.InnerText = p.AdditionalInfo;
xTop.AppendChild(xName);
xTop.AppendChild(xHometown);
xTop.AppendChild(xAddress);
xTop.AppendChild(xBirthday);
xTop.AppendChild(xPhone);
xTop.AppendChild(xEmail);
xTop.AppendChild(xAdditionalInfo);
xDoc.DocumentElement.AppendChild(xTop);
}

xDoc.Save(phonebook_path);
Sync();
SetStartup();
}


I also added this in my "Add" method to make sure there is no double contacts.

C#
if (people.Find(x => x.Name == p.Name) == null) {  // I modifed this part
people.Add(p);
listView1.Items.Add(p.Name);
}
else {
MessageBox.Show("That contact already exists!");
}
 
Share this answer
 
To answer your query more directly, do things work when you remove a single item at a time? This part, where you remove a single item from your generic list and then a whole set of selected items from your UI control, appears to be a problem:
people.RemoveAt(listView1.SelectedItems[0].Index);
foreach (ListViewItem eachItem in listView1.SelectedItems)
{
    listView1.Items.Remove(eachItem);
}

See if this gets you closer to functional:
C#
foreach (ListViewItem eachItem in listView1.SelectedItems)
{
    people.RemoveAt(eachItem.Index);
    listView1.Items.Remove(eachItem);
}
 
Share this answer
 
Comments
Exinta Ennea 27-Nov-13 17:22pm    
Yes, removing a single item works fine but as I said, after I remove several items (one by one) the error apperas. On the other hand, if somehow no error appears after deleting several items (usually it is possible to remove only 4-5-6 items before it appears) and there is only one item left, it is not possible to remove it. It does get deleted from the listview, but when I load the app again, the contact would still be there - like I have never removed it.

I have tried the way you suggested, but still getting the error.
woopsydoozy 29-Nov-13 12:08pm    
Sorry, there's too much code here for me to spend time reproducing or reading through it all. Narrow down the problem. Put a breakpoint in your Remove method and check each time through it to see if people.count is ever <> listView1.Items.count, and if so, try to figure out why. Check both at the start and end of the method--if it becomes out of synch at the start of the method, then presumably some other method is removing an item and needs to be fixed; if it gets out of synch at the end of Remove, then your problem is in Remove.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900