Listbox horizontal scrollbar not updating properly

I have a form that contains a list control with many other controls that define the contents of the list. Adding items to the list correctly sets the scrollbar range, but updating the items in the list (via this.lstResources.Items [index] = myUri) causes the scrollbar range to shrink beyond the maximum width of the item, cutting off the last few characters. The scrollbar still works, but updating the list in this way causes an unexpected and unacceptable scroll range for the item (s) in the list. This is how I implement my list:

public System.Windows.Forms.ListBox lstResources;
this.lstResources = new System.Windows.Forms.ListBox();

this.lstResources.FormattingEnabled = true;
this.lstResources.HorizontalScrollbar = true;
this.lstResources.Location = new System.Drawing.Point(331, 122);
this.lstResources.Name = "lstResources";
this.lstResources.Size = new System.Drawing.Size(307, 316);
this.lstResources.TabIndex = 8;
this.lstResources.Click += new System.EventHandler(this.ResourcesPage.LstResources_Click);

      

The change operations I am performing in this list are as follows:

this.parentClassReference.lstResources.Items.Add(myUri);
this.parentClassReference.lstResources.Items[index] = myUri;
this.parentClassReference.lstResources.Items.RemoveAt(index);

      

I tried Refresh () and Update () on both the form and the listbox control, but it has no effect. I've looked at all the list scrolling problems, but none of them have this specific redrawing problem.

This is how it should look:
enter image description here

This is what is actually happening:
enter image description here

I have a feeling that I am missing something obvious or perhaps changing elements incorrectly, but I am fresh out of ideas for this. I'm not entirely new to C # and UI design, but I can't say that I know all tightly controlled operations. Any help would be much appreciated.

EDIT 1: This is a sample that should reproduce the problem. I had a suspicion that the StringBuilder might have something to do with the update part, but it is also used in the btnAdd_Click code ...

public partial class SampleListBoxForm : Form
{
    public Dictionary<string, string> CurrentUriQuery { get; set; }

    public SampleListBoxForm()
    {
        this.CurrentUriQuery = new Dictionary<string, string>();
        this.InitializeComponent();
    }

    private void btnAdd_Click(object sender, EventArgs e)
    {
        this.UpdateParams("sampleApp");
        this.listBox1.Items.Add(this.GenerateURI());
        this.listBox1.Refresh();
    }

    private void btnUpdate_Click(object sender, EventArgs e)
    {
        int index = 0;
        this.UpdateParams("sampleApp2");
        for (; index < this.listBox1.Items.Count; index++)
        {
            this.listBox1.Items[index] = this.GenerateURI();
        }
    }

    private void UpdateParams(string filename)
    {
        this.CurrentUriQuery = new Dictionary<string, string>();
        this.CurrentUriQuery["filename"] = filename;
        this.CurrentUriQuery["url"] = @"C:\Users\me\Desktop\" + filename;
        this.CurrentUriQuery["type"] = "dynamicType";
        this.CurrentUriQuery["p1"] = "foo";
        this.CurrentUriQuery["p2"] = "bar";
        this.CurrentUriQuery["p3"] = "stuff";
        this.CurrentUriQuery["p4"] = "test";
    }

    private string GenerateURI()
    {
        StringBuilder currentUri = new StringBuilder();
        bool firstParam = true;
        currentUri.Append(this.CurrentUriQuery["filename"]);
        foreach (KeyValuePair<string, string> pair in this.CurrentUriQuery)
        {
            if (pair.Key != "url" && pair.Key != "filename" && pair.Value != string.Empty && pair.Value != "0")
            {
                if (firstParam)
                {
                    currentUri.Append("?");
                    firstParam = false;
                }
                else
                {
                    currentUri.Append("&");
                }

                currentUri.Append(pair.Key);
                currentUri.Append("=");
                currentUri.Append(pair.Value.Replace(" ", ""));
            }
        }

        return currentUri.ToString();
    }

    public string[] ExtractPathAndQueryFromUriString(string uriString)
    {
        string[] pathAndQuery = new string[2];
        if (uriString.Contains('?'))
        {
            pathAndQuery[0] = uriString.Split('?')[0];
            pathAndQuery[1] = uriString.Split('?')[1];
        }
        else if (uriString.Contains("%3F"))
        {
            string[] stringSeparator = new string[] { "%3F" };
            pathAndQuery[0] = uriString.Split(stringSeparator, StringSplitOptions.None)[0];
            pathAndQuery[1] = uriString.Split(stringSeparator, StringSplitOptions.None)[1];
        }
        else
        {
            pathAndQuery[0] = uriString;
            pathAndQuery[1] = string.Empty;
        }

        return pathAndQuery;
    }
}

      

+3


source to share


1 answer


The problem seems to be related to the ampersand characters. When you add an item, it seems to measure correctly. When you update an element it is not.

This ugly hack looks like this: write down the index, remove the element, insert the element back into that registered index.

Or switch to DrawMode = OwnerDrawFixed

and compute a value HorizontalExtent

for each item you add or change.

private void ResizeListBox() {
  int maxWidth = 0;

  for (int i = 0; i < listBox1.Items.Count; i++) {
    int testWidth = TextRenderer.MeasureText(listBox1.Items[i].ToString(), 
                                             listBox1.Font, listBox1.ClientSize,
                                             TextFormatFlags.NoPrefix).Width;
    if (testWidth > maxWidth)
      maxWidth = testWidth;
  }

  listBox1.HorizontalExtent = maxWidth;
}

      



Unfortunately, you have to call it for every change:

private void btnAdd_Click(object sender, EventArgs e) {
  this.UpdateParams("sampleApp");
  this.listBox1.Items.Add(this.GenerateURI());
  ResizeListBox();
}

private void btnUpdate_Click(object sender, EventArgs e) {
  this.UpdateParams("sampleApp");
  for (int index = 0; index < this.listBox1.Items.Count; index++) {
    this.listBox1.Items[index] = this.GenerateURI();
  }
  ResizeListBox();
}

      

Here's a quick and dirty version of DrawItem:

private void listBox1_DrawItem(object sender, DrawItemEventArgs e) {
  e.DrawBackground();
  if (e.Index > -1) {
    Color textColor = SystemColors.WindowText;
    if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) {
      textColor = SystemColors.HighlightText;
    }
    TextRenderer.DrawText(e.Graphics, listBox1.Items[e.Index].ToString(), 
                          listBox1.Font, e.Bounds, 
                          textColor, Color.Empty, TextFormatFlags.NoPrefix);
  }
}

      

+2


source







All Articles