在ObjectListView中保存和恢复选择

本文关键字:恢复 选择 保存 ObjectListView | 更新日期: 2023-09-27 18:15:51

谁能告诉我如何在ObjectListView中保持选择?

我有一个对象列表在我的控制,我从数据库接收。用户选择一个,然后点击"刷新"(以便再次从数据库检索所有项目)。选择是"跳跃",但我希望它保持在一个用户选择的对象。

我必须根据对象的唯一id来比较它们,这样从数据库中排序或新对象就不会影响用户的选择。

在ObjectListView中保存和恢复选择

这是我的解决方案(基于Barry Guvenkaya的答案)。我假设

  1. 可以选择多个项目(通过鼠标或键盘)
  2. 对象ID不是存储在olvlisttitem的列中,而是存储在对象内部(列可以隐藏,其顺序可以不同)。

My Refresh() function:

PushSelected();
objectListView.SetObjects(...);
PopSelected();

保存和恢复选择:

private List<Guid> selected;   // Keeping the ID's of selected objects
public void PushSelected()
{
    // Value of SelectedList can be get using
    // objectListView.SelectedObjects
    selected.Clear();
    foreach (MyObject r in SelectedList)  
        selected.Add(r.id);
}
public void PopSelected()
{
    D.DeselectAll();
    if (selected.Count != 0)
        for (int i = 0; i < objectListView.Items.Count; i ++)
        {
            OLVListItem item = (OLVListItem)objectListView.Items[i];
            Guid g = ((MyObject)item.RowObject).id;
            if (selected.Contains(g))
                item.Selected = true;
        }
 }

当然,这个解的复杂度也是O(n),如果所有项都被选中,复杂度甚至是O(n*n)。

Issue:

一旦您清除对象并再次构建列表,无论您是否将其保存在变量中,所选项目都会消失。因为要保留这些信息,必须将所选项的变量声明为动态附加到OLV控制的变量。这就是为什么一旦列表被清除,变量将无法保留选中的项。

关于处理:

我有一个解决这个问题的方法。大多数人可能会想到实现objectListViewUserList.SelectedItem属性,但这种属性存在一些问题。这与某种原因不一致。为了解决这个问题,我将引入objectListViewUserList.MouseMoveHitTest这个性质。这听起来像是一个测试变量,但它很有魅力。

假设:

另外,为了实现这个解决方案,假设第一列是ID列。

处理:

这是解决方法。在单击事件中将第一列的文本信息保存在公共字符串中。

    private void objectListViewUserList_Click(object sender, EventArgs e)
    {
        if (objectListViewUserList.MouseMoveHitTest.Item != null)
            selectedItemText = objectListViewUserList.MouseMoveHitTest.Item.Text;
        else
            selectedItemText = "";
    }

在我的应用程序中,我用fillOnlineUsers方法刷新OLV控件。这是任意的。它可以是任何方法。在我的应用程序中,此方法与计时器一起工作。每次刷新后,我通过搜索新列表中的ID来选择项目。

    public void fillOnlineUsers()
    {
        objectListViewUserList.ClearObjects();
        objectListViewUserList.AddObjects(onlineUsers);
        objectListViewUserList.BuildList();
        if (selectedItemText != "")
        {
            foreach (OLVListItem olvi in objectListViewUserList.Items)
                if (olvi.Text == selectedItemText)
                    olvi.Selected = true;
        }
    }

这个解决方法的复杂度为0 (n)。这意味着如果您有数千条记录,则可能会减慢应用程序的速度。

如果你使用2.9.1版本的ObjectListView,只使用olv.SetObjects(YourDataObject)现有的选择将被保留,您不需要任何耗时的方法或变通方法来记住活动的选择。

如果可能的话,您的代码应该尝试维护Data中的原始对象,并在需要时更新这些对象。如果您清除所有对象并重新创建新对象,您将失去选择,并被迫采用其他方法来记住选择

所以从其他帖子看来,你的记录有一个Guid,这是个好消息!如果你实现了GetHashCodeEquals,那么你可以通过传递旧列表olv.SelectedObjects.Cast<object>().ToList()来清除列表并重新选择旧的选择。

public partial class Form1 : Form
{
    private Guid _guid1;
    private Guid _guid2;
    class MyClass
    {
        public readonly Guid Guid;
        public string Key;
        public string Value;

        public MyClass(Guid guid, string key, string value)
        {
            Key = key;
            Guid = guid;
            Value = value;
        }
        public override int GetHashCode()
        {
            return Guid.GetHashCode();
        }
        public override bool Equals(object obj)
        {
            if (obj is MyClass)
                return this.Guid.Equals(((MyClass) obj).Guid);
            return base.Equals(obj);
        }
    }

    public Form1()
    {
        InitializeComponent();
        olv.FullRowSelect = true;
        olv.HideSelection = false;
        _guid1 = Guid.Parse("026c90aa-7fb8-452d-b8bc-b42fd7bc0e7f");
        _guid2 = Guid.Parse("85ea0ce0-da65-412f-8198-724c196342da");
        olv.AddObjects(new []
        {
            //two objects that will be updated
            new MyClass(_guid1,"go","nuts"), 
            new MyClass(_guid2,"lol","rly?"),
            //one object that will disapear
            new MyClass(Guid.NewGuid(),"bye","bye")
        });
    }
    private void BtnRefreshObjects_Click(object sender, System.EventArgs e)
    {
        olv.BeginUpdate();
        //remember the old objects
        var oldSelection = olv.SelectedObjects.Cast<object>().ToList();
        //swap them for the new objects
        olv.ClearObjects();
        olv.AddObjects(
            new []
        {
            //This object stays the same
            new MyClass(_guid1,"go","nuts"), 
            //This object changes fields (but is still the same record due to Guid)
            new MyClass(_guid2,"omg2","omg3"),
            //This is a new object
            new MyClass(Guid.NewGuid(),"omg5","omg6")
        });
        //reset the old selection (even though they are stale objects the selection works because of Equality override)
        olv.SelectedObjects = oldSelection;
        olv.EndUpdate();
    }
}