代码之家  ›  专栏  ›  技术社区  ›  Paul Michaels

.NET Listview刷新

  •  5
  • Paul Michaels  · 技术社区  · 14 年前

    我有以下代码,基本上从数据库中获取值并填充listview。

    using (IDataReader reader = cmd.ExecuteReader())
    {                    
        lvwMyList.Items.Clear();
        while (reader.Read())
        {
            ListViewItem lvi = lvwMyList.Items.Add(reader["Value1"].ToString());
            lvi.SubItems.Add(reader["Value2"].ToString());                    
        }
    }
    

    我遇到的问题是,这是重复执行很短的时间间隔(每秒钟),并在listview中的项目结果不断消失和重新出现。有什么方法可以阻止listview在更新完成之前刷新吗?如下所示:

    using (IDataReader reader = cmd.ExecuteReader())
    {                    
        lvwMyList.Items.Freeze(); // Stop the listview updating
        lvwMyList.Items.Clear();
        while (reader.Read())
        {
            ListViewItem lvi = lvwMyList.Items.Add(reader["Value1"].ToString());
            lvi.SubItems.Add(reader["Value2"].ToString());                    
        }
        lvwMyList.Items.UnFreeze(); // Refresh the listview
    }
    
    3 回复  |  直到 14 年前
        1
  •  9
  •   jgauffin    11 年前

    这样地:

    try
    {
        lvwMyList.BeginUpdate();
        //bla bla bla
    
    }
    finally
    {
        lvwMyList.EndUpdate();
    }
    

    lvwMyList.Items.Clear() 之后 BeginUpdate 如果你想在填表之前把它清空。

        2
  •  2
  •   Alex    7 年前

    这是我第一次在StackOverflow上发帖,所以请原谅下面混乱的代码格式。

    为了防止在更新ListView时锁定窗体,可以使用下面我编写的方法来解决此问题。

    注: 如果希望用大约20000个项目填充ListView,则不应使用此方法。如果需要向ListView添加超过20k个项目,请考虑以虚拟模式运行ListView。

     public static async void PopulateListView<T>(ListView listView, Func<T, ListViewItem> func, 
            IEnumerable<T> objects, IProgress<int> progress) where T : class, new()
        {
            if (listView != null && listView.IsHandleCreated)
            {
                var conQue = new ConcurrentQueue<ListViewItem>();
    
                // Clear the list view and refresh it
                if (listView.InvokeRequired)
                {
                    listView.BeginInvoke(new MethodInvoker(() =>
                        {
                            listView.BeginUpdate();
                            listView.Items.Clear();
                            listView.Refresh();
                            listView.EndUpdate();
                        }));
                }
                else
                {
                    listView.BeginUpdate();
                    listView.Items.Clear();
                    listView.Refresh();
                    listView.EndUpdate();
                }
    
                // Loop over the objects and call the function to generate the list view items
                if (objects != null)
                {
                    int objTotalCount = objects.Count();
    
                    foreach (T obj in objects)
                    {
                        await Task.Run(() =>
                            {
                                ListViewItem item = func.Invoke(obj);
    
                                if (item != null)
                                    conQue.Enqueue(item);
    
                                if (progress != null)
                                {
                                    double dProgress = ((double)conQue.Count / objTotalCount) * 100.0;
    
                                    if(dProgress > 0)
                                        progress.Report(dProgress > int.MaxValue ? int.MaxValue : (int)dProgress);
                                }
                            });
                    }
    
                    // Perform a mass-add of all the list view items we created
                    if (listView.InvokeRequired)
                    {
                        listView.BeginInvoke(new MethodInvoker(() =>
                            {
                                listView.BeginUpdate();
                                listView.Items.AddRange(conQue.ToArray());
                                listView.Sort();
                                listView.EndUpdate();
                            }));
                    }
                    else
                    {
                        listView.BeginUpdate();
                        listView.Items.AddRange(conQue.ToArray());
                        listView.Sort();
                        listView.EndUpdate();
                    }
                }
            }
    
            if (progress != null)
                progress.Report(100);
        }
    

    您不必提供IProgress对象,只需使用null,该方法也能正常工作。

    首先,定义一个包含ListViewItem数据的类。

    public class TestListViewItemClass
    {
        public int TestInt { get; set; }
    
        public string TestString { get; set; }
    
        public DateTime TestDateTime { get; set; }
    
        public TimeSpan TestTimeSpan { get; set; }
    
        public decimal TestDecimal { get; set; }
    }
    

    然后,创建一个返回数据项的方法。此方法可以查询数据库、调用web服务API或其他任何方法,只要它返回类类型的IEnumerable。

    public IEnumerable<TestListViewItemClass> GetItems()
    {
        for (int x = 0; x < 15000; x++)
        {
            yield return new TestListViewItemClass()
            {
                TestDateTime = DateTime.Now,
                TestTimeSpan = TimeSpan.FromDays(x),
                TestInt = new Random(DateTime.Now.Millisecond).Next(),
                TestDecimal = (decimal)x + new Random(DateTime.Now.Millisecond).Next(),
                TestString = "Test string " + x,
            };
        }
    }
    

    我已经包含了一个函数,该函数从我的类TestListViewItemClass的实例生成ListViewItem。在生产场景中,您可能希望在其他地方定义函数。

    private async void TestListViewForm_Load(object sender, EventArgs e)
    {     
        var function = new Func<TestListViewItemClass, ListViewItem>((TestListViewItemClass x) =>
        {
            var item = new ListViewItem();
    
            if (x != null)
            {
                item.Text = x.TestString;
                item.SubItems.Add(x.TestDecimal.ToString("F4"));
                item.SubItems.Add(x.TestDateTime.ToString("G"));
                item.SubItems.Add(x.TestTimeSpan.ToString());
                item.SubItems.Add(x.TestInt.ToString());
                item.Tag = x;
    
                return item;
            }
    
            return null;
        });
    
           PopulateListView<TestListViewItemClass>(this.listView1, function, GetItems(), progress);
    
     }
    

    在上面的示例中,我在窗体的构造函数中创建了一个IProgress对象,如下所示:

    progress = new Progress<int>(value =>
    {
        toolStripProgressBar1.Visible = true;
    
        if (value >= 100)
        {
            toolStripProgressBar1.Visible = false;
            toolStripProgressBar1.Value = 0;
        }
        else if (value > 0)
        {
            toolStripProgressBar1.Value = value;
        }
     });
    

    希望这是有帮助的。

    public static Task PopulateListViewAsync<T>(ListView listView, Func<T, ListViewItem> func,
            IEnumerable<T> objects, IProgress<int> progress) where T : class, new()
    {
        return Task.Run(() => PopulateListView<T>(listView, func, objects, progress));
    }
    
        3
  •  0
  •   Beth    14 年前

    您还可以尝试在更新期间将visible或enabled属性设置为false,看看您是否更喜欢这些结果。 当然,更新完成后,将值重置为true。