2012-04-10 71 views
3

我有一个窗体,其中包含一个列表框控件与许多其他控件确定列表框内容。将项目添加到列表框正确设置滚动条的范围,但更新列表框上的项目(通过this.lstResources.Items [index] = myUri)会导致滚动条的范围减少到最大项目的宽度,从而截断最后几个字符。滚动条仍然有效,但以这种方式更新列表框会导致意外且无法接受的列表中项目的滚动范围。这里是我如何实现我的列表框:列表框水平滚动条没有正确更新

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); 

,我在这个列表框进行的改变操作如下:

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

我已经从表格上试图刷新()和Update()和列表框控件,但都没有任何作用。我查看了所有的列表框滚动条问题,但没有人似乎有这个奇怪的重绘问题。

这是它应该是什么样子:
enter image description here

这是实况:
enter image description here

我有一种感觉,我缺少明显的东西或者是改变不正确的项目,但是我对这个想法很新鲜。我并不是全新的C#和UI设计,但我不能说我知道所有的基本控制操作。任何援助将不胜感激。

编辑1:这是一个应该重现问题的示例表单。我开始有一个怀疑,StringBuilder的可能有一些做的更新的一部分,但它也可用于在btnAdd_Click代码以及...

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; 
    } 
} 
+0

不能复制。更改ListBox项目会更改滚动条范围。 – LarsTech 2012-04-10 17:01:01

+0

有没有办法跟踪滚动条的范围,以便我可以自己调试?非公有财产也许?我会提供更多的代码,但我认为其余部分不相关。我遍历每个列表项来更新它们,但这是关于相关外部代码的范围。 编辑:这可能有助于知道这些操作不在与列表框相同的对象中执行,这就是为什么它是公开的。 – covertCoder 2012-04-10 17:23:54

+0

反过来做。用最少量的代码创建一个新项目并重现问题。发布该代码。您正在查看其他人无法看到的代码,这很难提供帮助。 – LarsTech 2012-04-10 17:28:52

回答

2

的问题似乎是通过符号。当您添加该项目时,它似乎正确测量。当您更新该项目时,它不会。

这个丑陋的黑客似乎是:记录索引,删除项目,插入项目回记录索引。

或切换到DrawMode = OwnerDrawFixed并计算您添加或更改的每个项目的HorizontalExtent值。

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; 
} 

不幸的是,你必须把它的每一个变化:

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(); 
} 

这里是一个快速和肮脏的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); 
    } 
} 
+0

哇,这太棒了!我会通过这个工作并让你知道它是如何发展的。只要它是C#的错误,我就可以用'丑陋'的代码开始,它看起来就是这样。 – covertCoder 2012-04-10 19:50:44

+0

工程就像一个魅力(ResizeListBox()至少),非常感谢您的时间和精力LarsTech。 – covertCoder 2012-04-10 20:17:04

+1

我需要使用TextFormatFlags.SingleLine | TextRenderer.MeasureText()中的TextFormatFlags.NoPrefix使其工作。 – huha 2014-03-03 13:56:11