我正在编写一个程序,它会在大屏幕上显示几个列表框中的数字列表。我的问题是是否有一种自动滚动列表框以显示框中所有数据的方法?
我正在编写一个程序,它会在大屏幕上显示几个列表框中的数字列表。我的问题是是否有一种自动滚动列表框以显示框中所有数据的方法?
通常,我会这样做:
listBox.SelectedIndex = listBox.Items.Count - 1;
listBox.SelectedIndex = -1;
该方法
。int nItems = (int)(listBox.Height / listBox.ItemHeight);
listBox.TopIndex = listBox.Items.Count - nItems;
如果您需要直接控制滚动而不选择项目,则需要使用来自User32.dll
的Win32 SetScrollPos
方法。以下是一个扩展类,它为您提供基本支持:
public class ScrollableListView : ListView
{
private const int WM_VSCROLL = 0x115;
private enum ScrollBar : int { Horizontal = 0x0, Vertical = 0x1 }
public void SetScroll(int x, int y)
{
this.SetScroll(ScrollBar.Horizontal, x);
this.SetScroll(ScrollBar.Vertical, y);
}
public void SetScrollX(int position)
{
this.SetScroll(ScrollBar.Horizontal, position);
}
public void SetScrollY(int position)
{
this.SetScroll(ScrollBar.Vertical, position);
}
[DllImport("User32.Dll", EntryPoint = "PostMessageA")]
private static extern bool PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
[DllImport("user32.dll")]
private static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw);
private void SetScroll(ScrollBar bar, int position)
{
if (!this.IsDisposed)
{
ScrollableListView.SetScrollPos((IntPtr)this.Handle, (int)bar, position, true);
ScrollableListView.PostMessage((IntPtr)this.Handle, ScrollableListView.WM_VSCROLL, 4 + 0x10000 * position, 0);
}
}
}
public enum ScrollBarDirection : int { Horizontal = 0x0, Vertical = 0x1 }
为了滚动命令代码本身,我们还需要另一个枚举 - 我们只保留了Up (SB_LINEUP
), Down (SB_LINEDOWN
)和EndScroll(SB_ENDSCROLL
)。在滚动消息之后,需要EndScroll以通知控件进行更新。
public enum ScrollCommand : int { Up = 0x0, Down = 0x1, EndScroll = 0x8 }
最后是类本身。它基本上通过向下滚动开始,每20毫秒一次(默认情况下 - 请注意,可以通过MarqueeSpeed属性进行更改)。然后获取滚动位置,并将其与上次进行比较。一旦滚动条停止移动,它就会反转方向。这是为了解决我使用GetScrollInfo方法时遇到的问题。
public class MarqueeListView : ListView
{
protected const int WM_VSCROLL = 0x115;
private ScrollCommand scrollCommand;
private int scrollPositionOld;
private Timer timer;
public MarqueeListView()
: base()
{
this.MarqueeSpeed = 20;
this.scrollPositionOld = int.MinValue;
this.scrollCommand = ScrollCommand.Down;
this.timer = new Timer() { Interval = this.MarqueeSpeed };
this.timer.Tick += (sender, e) =>
{
int scrollPosition = MarqueeListView.GetScrollPos((IntPtr)this.Handle, (int)ScrollBarDirection.Vertical);
if (scrollPosition == this.scrollPositionOld)
{
if (this.scrollCommand == ScrollCommand.Down)
{
this.scrollCommand = ScrollCommand.Up;
}
else
{
this.scrollCommand = ScrollCommand.Down;
}
}
this.scrollPositionOld = scrollPosition;
MarqueeListView.SendMessage((IntPtr)this.Handle, MarqueeListView.WM_VSCROLL, (IntPtr)this.scrollCommand, IntPtr.Zero);
MarqueeListView.SendMessage((IntPtr)this.Handle, MarqueeListView.WM_VSCROLL, (IntPtr)ScrollCommand.EndScroll, IntPtr.Zero);
};
this.timer.Start();
}
public int MarqueeSpeed
{
get
{
return this.timer.Interval;
}
set
{
this.timer.Interval = value;
}
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern int GetScrollPos(IntPtr hWnd, int nBar);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
protected static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
}
private static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form form = new Form() { StartPosition = FormStartPosition.CenterScreen, Width = 1280, Height = 720 };
MarqueeListView list = new MarqueeListView() { View = View.Tile, Dock = DockStyle.Fill };
for (int i = 0; i < 1000; i++) { list.Items.Add(Guid.NewGuid().ToString()); }
form.Controls.Add(list);
Application.Run(form);
}
SetScrollPos
,这将产生更好、更平滑的效果。您可以轻松地包括加速和减速 - 可能选择在鼠标悬停时缓慢停止,然后在鼠标移出时加速等等。目前它只是无法正常工作 - 我在旧项目中有一个可用的滚动更新方法,所以如果我再次使其工作,我会更新此内容。MarqueeListView
。 - undefinedSelectedIndex
。但是它确实还有另一个问题 - 如果ListView正在使用其中一种图标或磁贴视图,那么很难控制速度,因为它会在项目之间循环滚动,所以采用Win32滚动消息的方法更适合。 - undefinedListBox1.ScrollIntoView(ListBox1.Items[ListBox1.Items.Count - 1]);
或者您可以使用以下代码在顶部插入您的项目:
lbLog.Items.Insert(0,"日志项");
listBox.SelectedIndex = number;
或listBox.SelectedItem = "string";
),列表框会自动滚动到所选项目。 - undefined