#c# #winforms #listview #scrollbar #autoscroll
Вопрос:
Я хочу автоматически прокручивать представление списка по горизонтали до последнего столбца каждый раз, когда добавляется заголовок столбца.
Мне нужно только прокрутить до последнего столбца, а не до элемента.
listView1.Alignment
установлен в левое положениеlistView1.View
устанавливается вView.Details
Я пробовал это, но это ничего не дает:
listView1.AutoScrollOffset = new Point(listView1.AutoScrollOffset.X-10, 0);`
Это работает только в том случае, если я добавляю только элементы:
listView1.EnsureVisible(0);
string rowstr = "Test,";
for (var i = 0; i < 10; i )
{
Debug.WriteLine(i);
ColumnHeader head = new ColumnHeader();
head.Text = i.toString();
listView1.Columns.Add(head);
listView1.Columns[i].Width = 65;
rowstr = "Test" ",";
string[] row = rowstr.Split(",");
var listViewItem = new ListViewItem(row);
listViewItem.Font = new Font("Consolas", 10f);
listView1.Items.Insert(0, listViewItem);
//listView1.EnsureVisible(0);
listView1.AutoScrollOffset = new Point(listView1.AutoScrollOffset.X-10, 0);
}
Я не пытался переопределить WndProc или вызвать функцию User32, но если это единственный вариант, любая помощь будет признательна.
Если бы это было возможно без пинвокинга, это было бы лучше.
Ответ №1:
Чтобы прокрутить представление списка по горизонтали, вы можете отправить в элемент управления сообщение LVM_SCROLL, установив wParam
значение, соответствующее позиции (в пикселях), на которую нужно прокрутить.
Положение относительно текущего смещения.
Установите lParam
для прокрутки по вертикали.
Поскольку вы хотите прокрутить до последнего столбца, а представление списка находится в Details
режиме, вы можете просто передать int.MaxValue
его как смещение: управление Win32 выполнит настройку (оно все равно это сделает).
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, int lParam);
private const int LVM_SCROLL = 0x1014;
SendMessage(listView1.Handle, LVM_SCROLL, int.MaxValue, 0);
Редактировать:
Измените свой код, добавив интервал между вставкой каждого столбца/элемента списка, чтобы увидеть его в замедленном режиме. Вы можете использовать Button.Click
обработчик.
private async void SomeButton_Click(object sender, EventArgs e)
{
for (int idx = 0; idx < 10; idx ) {
var head = new ColumnHeader() {
Text = idx.ToString(),
Width = 65
};
listView1.Columns.Add(head);
SendMessage(listView1.Handle, LVM_SCROLL, int.MaxValue, 0);
var rowArray = new List<string>(Enumerable.Range(0, idx 1).Select(n => $"Test{n}"));
var listViewItem = new ListViewItem(rowArray.ToArray());
listView1.Items.Insert(0, listViewItem);
SendMessage(listView1.Handle, LVM_SCROLL, int.MaxValue, 0);
await Task.Delay(500);
}
}
Удалите async
материал, чтобы освободить его.
Чтобы получить текущее положение прокрутки, при необходимости используйте GetScrollInfo(). Например.,
var scrollInfo = new SCROLLINFO(SBInfoMask.SIF_ALL);
bool result = GetScrollInfo(listView1.Handle, SBParam.SB_HORZ, ref scrollInfo);
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern bool GetScrollInfo(IntPtr hwnd, SBParam nBar, [In, Out] ref Point lpsi);
[StructLayout(LayoutKind.Sequential)]
internal struct SCROLLINFO
{
public uint cbSize;
public SBInfoMask fMask;
public int nMin;
public int nMax;
public uint nPage;
public int nPos;
public int nTrackPos;
public SCROLLINFO(SBInfoMask mask)
{
cbSize = (uint)Marshal.SizeOf<SCROLLINFO>();
fMask = mask;
nMin = 0; nMax = 0; nPage = 0; nPos = 0; nTrackPos = 0;
}
}
internal enum SBInfoMask : uint
{
SIF_RANGE = 0x1,
SIF_PAGE = 0x2,
SIF_POS = 0x4,
SIF_DISABLENOSCROLL = 0x8,
SIF_TRACKPOS = 0x10,
SIF_ALL = (SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS),
SIF_POSRANGE = (SIF_RANGE | SIF_POS | SIF_PAGE)
}
public enum SBParam : int
{
SB_HORZ = 0x0,
SB_VERT = 0x1,
SB_CTL = 0x2,
SB_BOTH = 0x3
}
Комментарии:
1. Моим решением также был user32 SendMessage.
private const int WM_HSCROLL = 0x114; private const int WPARAM = 7; SendMessage(listView1.Handle, WM_HSCROLL, WPARAM, 0);
Я использовал 0x114 для горизонтальной прокрутки и 7 в качестве Wparam, и это сработало, ниже 7 не прокручивалось до конца.2. Я попробовал ваше решение, и полоса прокрутки переходит к последнему столбцу, но после перехода всегда возвращается к началу при добавлении столбцов.
3. Я не знаю, как вы это реализовали. См. Пример редактирования.
4. Я добавил
SendMessage
после добавления столбца и добавления элемента, и мне нравится, что это работает.
Ответ №2:
Вы можете создать CustomListView
и Re_Define
EnsureVisible
метод
class DataFlowFilterListView : ListView
{
/// <summary>
/// margin from the selected column to the border of listview.
/// </summary>
const int MARGIN = 20;
/// <summary>
/// native windows message to scroll the listview.
/// </summary>
const Int32 LVM_FIRST = 0x1000;
const Int32 LVM_SCROLL = LVM_FIRST 20;
[DllImport("user32")]
static extern IntPtr SendMessage(IntPtr Handle, Int32 msg, IntPtr wParam,
IntPtr lParam);
private void ScrollHorizontal(int pixelsToScroll)
{
SendMessage(this.Handle, LVM_SCROLL, (IntPtr)pixelsToScroll,
IntPtr.Zero);
}
/// <summary>
/// Ensure visible of a ListViewItem and SubItem Index.
///
///
/// </summary>
/// <param name="item"></param>
/// <param name="subItemIndex"></param>
public void EnsureVisible(ListViewItem item, int subItemIndex)
{
if (item == null || subItemIndex > item.SubItems.Count - 1)
{
throw new ArgumentException();
}
// scroll to the item row.
item.EnsureVisible();
ScrollToRectangle(item.SubItems[subItemIndex].Bounds.Width);
}
/// <summary>
/// Scrolls the listview.
/// </summary>
/// <param name="bounds"></param>
private void ScrollToRectangle(int width)
{
this.ScrollHorizontal(width);
}
}
Теперь вы можете использовать DataFlowFilterListView
вместо ListView
.
Каждый раз, когда вы добавляете столбец в список, выполняйте следующий код
listView1.EnsureVisible(listView1.Items[0], 0);
Ответ №3:
Мое решение заключается в использовании функции user32 и SendMessage()
.
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);
private const int WM_HSCROLL = 0x114; //for horizontal scroll
private const int WPARAM = 7; //to scroll to end
Реализация:
string rowstr = "Code,"
for (var i = 0; i < 10; i )
{
ColumnHeader head = new ColumnHeader();
head.Text = i.toString();
listView1.Columns.Add(head);
listView1.Columns[i].Width = 65;
rowstr = "Test" ",";
string[] row = rowstr.Split(",");
var listViewItem = new ListViewItem(row);
listViewItem.Font = new Font("Consolas", 10f);
listView1.Items.Insert(0, listViewItem);
SendMessage(listView1.Handle, WM_HSCROLL, WPARAM, 0);
}