新しいアイテムを追加した後にリストボックスを自動スクロールするにはどうすればよいですか?ただし、アイテムが追加される前にスクロールバーが下部にある場合に限りますか?
4 に答える
あなたはそれを試すことができます:
listBox1.SelectedIndex = listBox1.Items.Count - 1;
listBox1.SelectedIndex = -1;
このサンプル コードが役に立ちます。私はこれを TextBox で何度もやったことがありますが、ListBox を理解するのに時間がかかりました
明らかに、これは Button と ListBox を備えた単なる Form です。ニーズに合わせて変更します。
private void button1_Click(object sender, EventArgs e)
{
listBox1.Items.Add("Some Text " + listBox1.Items.Count.ToString());
//The max number of items that the listbox can display at a time
int NumberOfItems = listBox1.ClientSize.Height / listBox1.ItemHeight;
if (listBox1.TopIndex == listBox1.Items.Count - NumberOfItems - 1)
{
//The item at the top when you can just see the bottom item
listBox1.TopIndex = listBox1.Items.Count - NumberOfItems + 1;
}
}
私は次の解決策を思いつきました。これは、高さが可変の項目を持つ所有者が描画したリストボックスでも機能します。
基本的な考え方は、IndexToPoint メソッドとリストボックスの下部にあるポイントを使用して、最後の項目がその位置にあるかどうかを確認することにより、下部までスクロールされているかどうかを判断することです。これには、最後のアイテムが一番下にあるが完全に表示されていない場合でも、一番下までスクロールされたと見なされるという小さな欠陥があります。
TopIndex プロパティを使用して、リスト ボックスをスクロールします。TopIndex をリストボックスの最後の項目に設定する場合、他の項目のための十分なスペースがある場合、実際にはそれを一番上に配置しないことに注意してください。その場合、それはあなたが望むものである一番下に置かれます。
また、いっぱいになった後に一番上のアイテムを削除することで、リスト内のアイテム数を最大数 (定数 MAX_LISTBOX_ITEMS によって別の場所で定義) に保つ追加のコードもあります。これを行うと、リストをスクロールして同じアイテムを削除した後でも同じアイテムを表示し続ける必要がある場所がわかります。リストボックスに追加されるアイテムの数を制御することを気にしない場合は、コードから中間の if 句と scrollToIndex 変数への言及を削除できるはずです。
private void AddItemToListBox(ListBox listBox, object newItem)
{
int scrollToIndex = -1;
bool scrollToEnd = false;
//Work out if we should scroll to the end after adding a new item
int lastIndex = listBox.IndexFromPoint(4, listBox.ClientSize.Height - 4);
if ((lastIndex < 0) || (lastIndex == listBox.Items.Count - 1))
{
scrollToEnd = true;
}
//To prevent listbox jumping about as we delete and scroll
listBox.BeginUpdate();
//Work out if we have too many items and have to delete
if (listBox.Items.Count >= MAX_LISTBOX_ITEMS)
{
//If deleting an item, and not scrolling to the end when new item added anyway,
//then we will need to scroll to keep in the same place, work out new scroll index
if (!scrollToEnd)
{
scrollToIndex = listBox.TopIndex - 1;
if (scrollToIndex < 0)
{
scrollToIndex = 0;
}
}
//Remove top item
listBox.Items.Remove(listBox.Items[0]);
}
//Add new item
listBox.Items.Add(newItem);
//Scroll if necessary
if (scrollToEnd)
{
listBox.TopIndex = listBox.Items.Count - 1;
}
else if (scrollToIndex >= 0)
{
listBox.TopIndex = scrollToIndex;
}
listBox.EndUpdate();
}
この問題は、colithium と同様の方法で解決しましたが、同時更新にバグがあることに気付きました。そのため、この更新が発生する前に ListBox にアイテムの数を格納する m_previousCount というクラス メンバーがあります。
私は ListView でこれを行いましたが、ListBox でも同じように機能するはずです。
この場合、listView1 は listViewModel1.Entries にコンテンツ バインドされています。
private void EventMessageViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
listView1.Dispatcher.BeginInvoke(DispatcherPriority.Background, new ScrollToLastItemDelegate(ScrollToLastItem));
}
/// <summary>
/// Scroll to last item, unless you have scrolled up the list
/// </summary>
private void ScrollToLastItem()
{
// Get scrollviewer
Decorator border = System.Windows.Media.VisualTreeHelper.GetChild(listView1, 0) as Decorator;
ScrollViewer scrollViewer = border.Child as ScrollViewer;
double vo = scrollViewer.VerticalOffset;
// assume they are all the same height
ListBoxItem lbi = listView1.ItemContainerGenerator.ContainerFromIndex(0) as ListBoxItem;
//The max number of items that the listbox can display at a time
double NumberOfItemsOnScreen = listView1.ActualHeight / lbi.ActualHeight;
// use previousCount in case we get multiple updates in one go
if (m_previousCount > NumberOfItemsOnScreen) // scrollbar should be active
{
if (vo < (m_previousCount - NumberOfItemsOnScreen)) // you're not at the bottom
{
return; // don't scroll to the last item
}
}
m_previousCount = listView1.Items.Count;
// scroll to the last item
listView1.SelectedItem = listView1.Items.GetItemAt(listViewModel1.Entries.Count - 1);
listView1.ScrollIntoView(listView1.SelectedItem);
}