Предотвращение автоматической прокрутки ListView по горизонтали при добавлении новых элементов - PullRequest
2 голосов
/ 23 марта 2012

Я использую элемент управления ListView в подробном представлении с VirtualMode, установленным на true, и обнаруживаю, что всякий раз, когда добавляется новый элемент, горизонтальная полоса прокрутки устанавливается в крайнее левое положение,Этого не происходит, если ListView не находится в виртуальном режиме. Обновление: этого также не произойдет, если вы не включите визуальные стили.

Это можно увидеть, создав простой ListView с двумя столбцами в режиме сведений и добавив что-то вродеследующее:

Timer timer = new Timer();

public Form1()
{
    this.InitializeComponent();

    this.listView1.VirtualMode = true;
    this.listView1.RetrieveVirtualItem += new RetrieveVirtualItemEventHandler(listView1_RetrieveVirtualItem);
    this.listView1.VirtualListSize = 10;

    timer.Interval = 250;
    timer.Tick += new EventHandler(t_Tick);
    timer.Start();
}

void listView1_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
{
    e.Item = new ListViewItem(new string[] {"Test", ""});
}

void t_Tick(object sender, EventArgs e)
{
    this.listView1.VirtualListSize += 1;
}

Прокрутите представление списка вправо, чтобы увидеть этот эффект.

Как я могу предотвратить это?У меня есть приложение, в котором элементы постоянно добавляются в представление списка, и поэтому это поведение очень отвлекает.

1 Ответ

5 голосов
/ 23 марта 2012

Это известная ошибка: ListView в виртуальном режиме неправильно прокручивается

Последний комментарий от Microsoft к этому отчету Connect:

Это проблема с базовым элементом управления Win32. Мы не сможем это исправить, команда ОС должна будет решить эту проблему.

Конечно, это было в 2005 году, так что, может быть, это исправлено в Win 8?


Тем временем, обходной путь выглядит так:

Создайте новый класс, который наследует ListView, и напишите следующий код:

private static FieldInfo _internalVirtualListSizeField;

static FlickerFreeListView()
{
    _internalVirtualListSizeField = typeof(ListView).GetField("virtualListSize", System.Reflection.BindingFlags.NonPublic | BindingFlags.Instance);
}

[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(HandleRef hWnd, int msg, int wParam, int lParam);

private IntPtr SendMessage(int msg, int wparam, int lparam)
{
    return SendMessage(new HandleRef(this, this.Handle), msg, wparam, lparam);
}

public void SetVirtualListSize(int size)
{
    if (size < 0)
    {
        throw new ArgumentException("ListViewVirtualListSizeInvalidArgument");
    }

    _internalVirtualListSizeField.SetValue(this, size);
    if ((base.IsHandleCreated && this.VirtualMode) && !base.DesignMode)
    {
        SendMessage(0x102f, size, 2);
    }
}

Теперь обновите свой код, чтобы использовать метод SetVirtualListSize вместо исходного свойства VirtualListSize.

0x102f = LVM_SETITEMCOUNT
2 = LVSICF_NOSCROLL

ссылка: http://msdn.microsoft.com/en-us/library/bb761188%28VS.85%29.aspx

...