在c#win表单中,如何滚动数百个项目

时间:2013-08-13 02:40:18

标签: c# winforms

是否存在允许用户在Windows窗体容器中滚动数百或数千个项目的常见设计?示例:编写电子邮件客户端,用户会得到平滑滚动超过10,000条消息“行”的印象,每封电子邮件一行 - 但这些肯定在它们显示之前才真正呈现。类似地,滚动一个巨大的图像必须要求将它拼凑成更小的部分,但代码是如何组织的呢?

2 个答案:

答案 0 :(得分:4)

它是Windows设计方式的先天,不需要3个字母或特殊模式。

GUI程序,无论其风格如何,只要预期执行操作,就会从Windows获取消息。消息不按生成顺序处理。有三个基本的“优先事项”:

  • 直接传递重要消息,底层winapi函数是SendMessage()
  • 用户输入首先存储在队列中,底层的winapi函数是PostMessage()
  • 某些消息是从窗口状态合成,只有在上述两种消息类型都不需要处理时才会生成。

按上述顺序处理消息。首先发送消息,如果没有待处理消息,则程序开始清空消息队列。如果它为空,则调度合成消息。绘画属于第3类。当 nothing else需要完成时,程序才会收到WM_PAINT消息。

因此,基本的事件链是控件从消息队列中检索鼠标消息并检测到它是否适用于滚动条。它计算滚动条拇指的新位置,并调用InvalidateRect()winapi函数以指示需要绘制窗口。与Winforms中的Invalidate()方法功能相同。更新内部窗口状态以标记需要绘制以重新绘制该矩形。这一切都非常快,没有真正的绘画。

当程序检索下一条消息时,现在可以发生两件基本事情。当用户继续滚动时,它可能再次是鼠标消息。以与上面完全相同的方式处理,除了改变拇指位置之外,窗口没有任何反应。

或者没有要处理的新消息,用户停止滚动,现在类别#3合成消息转向。 Windows注意到窗口需要重新绘制并传递WM_PAINT消息。

除此之外还有一些实现细节,Windows的更高版本默认情况下启用“拖动时显示窗口内容”系统选项。这使得用户在拖动拇指时更容易看到他正在做什么,它故意生成额外的窗口涂料。总而言之,操作系统和程序可以很好地支持ListView中的数万个项目。当然不是用户。

答案 1 :(得分:2)

如前所述,VirtualMode可能是最佳解决方案,有一个usage example on CodeProject

在表单创建时初始化虚拟模式:

private void Form1_Load(object sender, EventArgs e)
        {
            listView1.VirtualMode = true;       // switching virtual mode on
            listView1.VirtualListSize = 1000000000;     // give it 1 million lines
        }

然后分配并处理RetrieveVirtualItem事件:

private void listView1_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
   {
       ListViewItem lvi = new ListViewItem();   // create a listviewitem object
       lvi.Text = nt.MakeText(e.ItemIndex);         // assign the text to the item
       ListViewItem.ListViewSubItem lvsi = new ListViewItem.ListViewSubItem(); // subitem
       NumberFormatInfo nfi = new CultureInfo("de-DE").NumberFormat;
       nfi.NumberDecimalDigits = 0;
       lvsi.Text = e.ItemIndex.ToString("n", nfi);  // the subitem text
       lvi.SubItems.Add(lvsi);          // assign subitem to item

       e.Item = lvi;        // assign item to event argument's item-property
   }