防止列表视图丢失所选项目

问题描述 投票:7回答:6

我目前正在用winform c#制作一个列表视图,每次点击列表视图上的空位,选中的项目就会丢失。

c# winforms listview selection
6个回答
8
投票

列表视图控件有一个 HideSelection 属性,默认为 True. 让它 False 然后你就可以走了... 在某些情况下,这就足够了。


2
投票

我以为有一个属性可以防止这种情况发生,但现在我找不到了。

你可以试试这个。

private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    ListView listView = sender as ListView;
    if (listView.SelectedItems.Count == 0)
        foreach (object item in e.RemovedItems)
            listView.SelectedItems.Add(item);
}

2
投票

我是这样完成的

private void lvReads_MouseUp(object sender, MouseEventArgs e)
    {
        if (lvReads.SelectedItems.Count == 0)
            if (lvReads.Items.Count > 0)
                lvReads.Items.Find(currentName, false)[0].Selected = true;
    }

然后...

private void lvReads_SelectedIndexChanged(object sender, EventArgs e)
    {
        if (lvReads.SelectedItems.Count == 1)
        {               
            selectedIndex = lvReads.SelectedIndices[0];

            if (currentName != lvReads.Items[selectedIndex].Name)
            {

                //load item
            }

            currentName = lvReads.Items[selectedIndex].Name;
        }
    }

2
投票

你必须继承ListView类并做一些低级的消息处理。

class ListViewThatKeepsSelection : ListView
{
    protected override void WndProc(ref Message m)
    {
        // Suppress mouse messages that are OUTSIDE of the items area
        if (m.Msg >= 0x201 && m.Msg <= 0x209)
        {
            Point pos = new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16);
            var hit = this.HitTest(pos);
            switch (hit.Location)
            {
                case ListViewHitTestLocations.AboveClientArea:
                case ListViewHitTestLocations.BelowClientArea:
                case ListViewHitTestLocations.LeftOfClientArea:
                case ListViewHitTestLocations.RightOfClientArea:
                case ListViewHitTestLocations.None:
                    return;
            }
        }
        base.WndProc(ref m);
    }
}

1
投票

这在WinForms中比在WPF中更难做到。WinForms有一个 SelectedIndexChanged 事件,它不会告诉你任何关于已经选择的内容。加上 每当选择或取消选择一行时,它都会被触发。

所以,如果一行被选中后,你又选择了另一行,你就会收到两个 SelectedIndexChanged 事件。

  1. 在选定的行被取消选择后发生一次
  2. 当新的行被选中时,另一个事件就会发生。

问题是,在事件#1期间,ListView没有任何选择,你不知道事件#2是否会选择第二行。

你能做的最好的办法是等到你的应用程序空闲下来(在选择改变后的几毫秒),如果listview仍然没有任何选择,就把最后选择的行放回去。

private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
    ListView lv = (ListView)sender;
    if (lv.SelectedIndices.Count == 0)
    {
        if (!this.appIdleEventScheduled)
        {
            this.appIdleEventScheduled = true;
            this.listViewToMunge = lv;
            Application.Idle += new EventHandler(Application_Idle);
        }
    }
    else
        this.lastSelectedIndex = lv.SelectedIndices[0];
}

void Application_Idle(object sender, EventArgs e)
{
    Application.Idle -= new EventHandler(Application_Idle);
    this.appIdleEventScheduled = false;
    if (listViewToMunge.SelectedIndices.Count == 0) 
        listViewToMunge.SelectedIndices.Add(this.lastSelectedIndex);
}

private bool appIdleEventScheduled = false;
private int lastSelectedIndex = -1;
private ListView listViewToMunge;

0
投票

我知道这个问题问了10年了。但我也面临同样的问题,刚才找到了一个简单而优雅的解决方案,真心想分享一下。

有一个代码(在VB.NET中,但在C#中写同样的代码没有什么大问题)。

Public Class SettingsBox ' Form that contains ListView (lvScreen)

    Private nScreenTracer As Integer
    Private nSelectedScreen As Integer

    Private Sub lvScreen_ItemSelectionChanged(sender As Object,
                                              e As ListViewItemSelectionChangedEventArgs) Handles lvScreen.ItemSelectionChanged
        If e.IsSelected Then nScreenTracer = e.Item.Index
    End Sub

    Private Sub lvScreen_MouseDown(sender As Object,
                                   e As MouseEventArgs) Handles lvScreen.MouseDown
        nScreenTracer = -1
    End Sub

    Private Sub lvScreen_MouseUp(sender As Object,
                                 e As MouseEventArgs) Handles lvScreen.MouseUp
        If nScreenTracer = -1 Then
            lvScreen.SelectedIndices.Add(nSelectedScreen)
        Else
            nSelectedScreen = nScreenTracer
        End If
    End Sub

End Class

这个解决方案适用于单项选择,但也可以简单地用List(Of Integer)重新设计为多项选择。

© www.soinside.com 2019 - 2024. All rights reserved.