【问题标题】:prevent listview to lose selected item防止列表视图丢失所选项目
【发布时间】:2011-01-23 20:28:10
【问题描述】:

我目前正在使用 winform c# 处理列表视图 每次我点击列表视图上的空白区域时, 所选项目丢失。

【问题讨论】:

标签: c# winforms listview selection


【解决方案1】:

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

你可以试试这个:

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);
}

【讨论】:

  • @Grammarian - 问题没有具体说明它是 WPF、WinForms、ASP、Silverlight 还是其他任何东西。我刚刚回答了一个我碰巧在IDE中打开的那个。您应该使用您最喜欢的 C# 显示技术发布答案! :-)
  • @Jeffery 这不是批评。只是让新手明白为什么你的正确答案可能对他不起作用。
【解决方案2】:

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

因此,如果选择了一行并且您选择了不同的行,您会收到两个SelectedIndexChanged 事件:

  1. 选定行之后的一个被取消选择
  2. 选择新行时的另一个。

问题是,在事件 #1 期间,ListView 没有选择任何内容,并且您不知道事件 #2 是否即将到来,这将选择第二行。

您可以做的最好的事情是等到您的应用程序空闲(选择更改后的几毫秒),如果列表视图仍然没有选择,则放回最后选择的行。

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;

【讨论】:

    【解决方案3】:

    我是这样完成的:

    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;
            }
        }
    

    【讨论】:

      【解决方案4】:

      你必须从 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);
          }
      }
      

      【讨论】:

        【解决方案5】:

        listview 控件有一个HideSelection 属性,默认为True。让它False,你很高兴......在某些情况下,这就足够了。

        【讨论】:

        • 这并没有解决发布的问题,他没有在失去焦点时取消选择项目的问题。
        • 更正:他在取消选择项目时遇到问题。所选项目未突出显示,因为控件丢失了哪些项目被选中。
        【解决方案6】:

        我知道 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) 重新设计以进行多选

        【讨论】:

          猜你喜欢
          • 2014-05-29
          • 2012-09-30
          • 2012-09-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-08-26
          • 1970-01-01
          • 2011-08-26
          相关资源
          最近更新 更多