3

The basic goal is to create a Business Card for each contact and put that card in a FlowLayoutPanel. The card itself is comprised of about 10 labels and 3 comboboboxes.

It doesn't take too many business cards to cause initial population of the panel to take a long time. Maybe I can find a way to deal with this

However, a primary concern is crashing. It only takes about 200 or so cards to crash (run out of handles).

I agree there are paging methods that could be implemented since a user never will need to see more than will fit on 1 or 2 screens at a time, but writing paging routines might be pretty tough.

Any suggestions on how to maximize efficiency of this planned FlowLayoutPanel?

P.S. The main issue is running out of handles (too many controls in the panel). Must resolve this before worrying about speed.

Praveen Vinny
  • 2,372
  • 6
  • 32
  • 40
user1646737
  • 169
  • 7
  • This might give you some hints: http://stackoverflow.com/questions/835100/winforms-suspendlayout-resumelayout-is-not-enough – rene Sep 24 '12 at 14:40
  • Thanks for the fast reply, Rene. My primary concern is the issue of running out of handles. If I don't resolve this, there is no point worrying about speed. – user1646737 Sep 24 '12 at 14:51
  • 1
    You have no other option then to make your flowlayout virtual (or page, whatever is more convienant) – rene Sep 24 '12 at 14:56
  • I was afraid of that. Each business card has some comboboxes on it. So, I can't just render them as bitmaps. That leaves me with trying to implement some sort of paging method. I can hack around on it, but am hoping someone has done this before and can point me to an example. – user1646737 Sep 24 '12 at 15:00
  • 5
    An obvious solution is a ListBox with contact names and *one* business card to view/edit the selected one. – Hans Passant Sep 24 '12 at 16:49
  • Well, I suppose if you want to abandon the desired appearance of the UI, it's an option. I did not feel like I was ready to give up so fast. I changed the flowpanel autoscroll to false. I added a Hscroll right below the panel. I set the LargeChange and Maximum properties of the scroll bar to be the number of cards per page and total number of cards, respectively. Then, I set a scroll event on the Hscroll. When the event shows EndScroll, I test the hscroll.value, which tells me what "page" I am on. Then, if page has changed (I store the value of old page), I clear the panel. Cont. – user1646737 Sep 24 '12 at 19:00
  • After clearing the panel, I add from the list of total contacts by starting at the one which is at (scroll.value * LargeMove) + 1. I continue adding the contacts in order up to element number (scroll.value * LargeMove) + 1 + LargeMove. This works. Now, I need to do some clean-up, but it works. I described the process a bit roughly, and my math might be off by 1 card. But for anyone down the road, this appears to be how it's done. – user1646737 Sep 24 '12 at 19:07
  • 1
    The [maximum amount of window handler is 10K](http://blogs.msdn.com/b/oldnewthing/archive/2007/07/18/3926581.aspx), this is limitation of Windows core, and you can't jump over it. The only one possible solution is paging. – shfire Jul 04 '13 at 09:41

1 Answers1

0

Okay, how about:

Create a class to store the information necessary to recreate a business card (10 labels and 3 comboboboxes) as public, gettable/settable properties, and with an empty default public constructor. Then, serialize each business card as an xml (or binary) file using XmlSerializer into a single folder. Then, you could use something like string[] businessCards = Directory.GetFiles(Path.GetFullPath("mysettings\\businesscards")); to iterate through your long 'cached' list of business cards. Have class that manages adding/removing items from your FlowLayoutPanel by calling a function like: SerializableBusinessCardClass GetNextCard() {}. This would be fairly simple to implement. You could also serialize a List<SerializableBusinessCardClass> with a length of about 5 (or however many you wanted to load in at once) to a single XML file for maximum efficiency, or if you have a truly ridiculous amount of business cards (such that explorer lags when browsing the folder). While a binary serialization would be faster, the XML approach has the added benefit that your clients can specify new business cards they want you to display by creating the XML file yourself.

Here, I will give you a concrete example of how you would build and serialize such a data structure:

public class SerializableBusinessCard
{
    public SerializableBusinessCard()       { }
    public string Name                      { get; set; }
    public string Company                   { get; set; }
    public List<string> Labels              { get; set; }
    public List<ComboItem> ComboBoxes       { get; set; }

}

public class ComboItem
{   
    public ComboItem()              { }
    public string Name              { get; set; }
    public string Text              { get; set; }
    public int SelectedIndex        { get; set; }
    public Point Location           { get; set; }
    public Size size                    { get; set; }
    public List<string> Collection{ get; set; }
}

Usage:

    public void stackoverflow_BusinessCard_FlowLayoutPanel()
    {
        List<string> labels = new List<string>();

        labels.Add("Title");
        labels.Add("Description");
        labels.Add("Phone");
        labels.Add("Email");
        labels.Add("Address");
        labels.Add("label6");
        labels.Add("labelN");


        ComboItem cItem = new ComboItem();

        cItem.Collection = new List<string>();
        cItem.Collection.Add("Option1");
        cItem.Collection.Add("Option2");

        cItem.Name = "comboName";
        cItem.SelectedIndex = 0;
        cItem.Text = cItem.Collection[cItem.SelectedIndex];
        cItem.Location = new Point(50, 265);
        cItem.size = new Size(100,21);

        List<ComboItem> comboItems = new List<ComboItem>();
        comboItems.Add(cItem);


        SerializableBusinessCard bCard1 = new SerializableBusinessCard();

        bCard1.Name         = "CompanyXYZ_BlueTheme";
        bCard1.Company      = "CompanyXYZ";
        bCard1.Labels       = labels;
        bCard1.ComboBoxes   = comboItems;

        SerializeObjectXML("BusinessCard_392.xml",bCard1);

        SerializableBusinessCard loaded = DeserializeBusinessCardXML("BusinessCard_392.xml");
    }

Here is the serialization function:

    public void SerializeObjectXML(string filename,object obj)
    {
        using(StreamWriter streamWriter = new StreamWriter(filename))
        {
            XmlSerializer xmlSerializer = new XmlSerializer(obj.GetType());
            xmlSerializer.Serialize(streamWriter,obj);
        }
    }

Result:

<?xml version="1.0" encoding="utf-8"?>
<SerializableBusinessCard xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>CompanyXYZ_BlueTheme</Name>
  <Company>CompanyXYZ</Company>
  <Labels>
    <string>Title</string>
    <string>Description</string>
    <string>Phone</string>
    <string>Email</string>
    <string>Address</string>
    <string>label6</string>
    <string>labelN</string>
  </Labels>
  <ComboBoxes>
    <ComboItem>
      <Name>comboName</Name>
      <Text>Option1</Text>
      <SelectedIndex>0</SelectedIndex>
      <Location>
        <X>50</X>
        <Y>265</Y>
      </Location>
      <size>
        <Width>100</Width>
        <Height>21</Height>
      </size>
      <Collection>
        <string>Option1</string>
        <string>Option2</string>
      </Collection>
    </ComboItem>
  </ComboBoxes>
</SerializableBusinessCard>

And the deserializer:

        public static SerializableBusinessCard DeserializeBusinessCardXML(string filename)
        {
            SerializableBusinessCard result = new SerializableBusinessCard();
            using(StreamReader streamReader = new StreamReader(filename))
            {
                XmlSerializer xmlReader = new XmlSerializer(typeof(SerializableBusinessCard));
                result = (SerializableBusinessCard) xmlReader.Deserialize(streamReader);
            }
            return result;
        }

Hope this helps.

Adam White
  • 3,180
  • 1
  • 21
  • 18