【问题标题】:How to update text in a listview without clearing it如何更新列表视图中的文本而不清除它
【发布时间】:2017-03-08 03:29:39
【问题描述】:

我正在为一款读取所有敌人信息(位置、健康状况等)并将其相应地存储在列表视图中的游戏进行 hack。我目前正在使用这种方法:

        listView1.Items.Clear();
        string[] arr = new string[6];
        ListViewItem item;

        for (int i = 0; i < engine.maxPlayers; i++)
       {
           engine.enemy[i].readInfo(i);
        arr[0] = i.ToString()
        arr[1] = engine.enemy[i].name.ToString();
        arr[2] = engine.enemy[i].getRank(csgo.enemy[i].compRank);
        arr[3] = engine.enemy[i].Wins.ToString();
        arr[4] = engine.enemy[i].health.ToString();
        arr[5] = engine.enemy[i].armor.ToString();

        item = new ListViewItem(arr);
        listView2.Items.Add(item);
        }

每 200 毫秒执行一次,以确保实时信息。 这在一定程度上有效。它确实正确显示了所有内容。但是,它有两个大缺陷。 1:清零改写数据时常闪烁。 2:如果我的列表视图只有 10 列长并且我需要读取 20 位玩家的数据,我无法向下滚动查看最后 10 位玩家,因为每次清除时,它都会重置滚动条位置。

那么是否可以只更新特定文本的文本?假设我只想更新敌人 [3] 的健康状况并留下其余部分。这可以做到吗?我不需要重新绘制胜利和排名等信息,因为它们在游戏中不会改变。

【问题讨论】:

  • listView2.Items[row].SubItems[column].Text
  • 有什么办法防止闪烁?
  • 你可以尝试设置 DoubleBuffered stackoverflow.com/questions/442817/…
  • engine.maxPlayers 在游戏过程中发生变化?

标签: c# .net winforms


【解决方案1】:

我认为您必须首先用第一次调用的数据填充列表视图,然后每隔 500 毫秒到 1000 毫秒(我认为 200 毫秒没有任何作用),用新数据刷新列表视图。
比如:

        private void InitialPopulation()
        {
            var listOfItems = new List<ListViewItem>();

            for (int i = 0; i < engine.maxPlayers; i++)
            {
                engine.enemy[i].readInfo(i);

                var item = new ListViewItem(i.ToString());
                item.Name = engine.enemy[i].name;
                item.SubItems.Add(engine.enemy[i].name);
                item.SubItems.Add(engine.enemy[i].getRank);
                item.SubItems.Add(engine.enemy[i].Wins);
                item.SubItems.Add(engine.enemy[i].health);
                item.SubItems.Add(engine.enemy[i].armor);

                listOfItems.Add(item);
            }

            listView1.BeginUpdate();
            listView1.Items.Clear();
            listView1.Items.AddRange(listOfItems.ToArray());
            listView1.EndUpdate();
        }

        private void RefreshData()
        {
            listView1.BeginUpdate();
            var listOfItems = new List<ListViewItem>();
            var playersNames = new List<string>();
            var itemsNames = new List<string>();


            for (int i = 0; i < engine.maxPlayers; i++)
            {
                engine.enemy[i].readInfo(i);

                playersNames.Add(engine.enemy[i].name);

                var items = listView1.Items.Find(engine.enemy[i].name, false);

                switch (items.Length)
                {
                    case 1: // update
                        items[0].SubItems[0].Text = engine.enemy[i].name;
                        items[0].SubItems[1].Text = engine.enemy[i].getRank;
                        items[0].SubItems[2].Text = engine.enemy[i].Wins;
                        items[0].SubItems[3].Text = engine.enemy[i].health;
                        items[0].SubItems[4].Text = engine.enemy[i].armor;
                        break;

                    case 0: // add
                        var item = new ListViewItem(i.ToString());
                        item.Name = engine.enemy[i].name;
                        item.SubItems.Add(engine.enemy[i].name);
                        item.SubItems.Add(engine.enemy[i].getRank);
                        item.SubItems.Add(engine.enemy[i].Wins);
                        item.SubItems.Add(engine.enemy[i].health);
                        item.SubItems.Add(engine.enemy[i].armor);
                        listOfItems.Add(item);
                        break;
                }
            }


            if (listOfItems.Count > 0)
                listView1.Items.AddRange(listOfItems.ToArray());

            foreach (ListViewItem item in listView1.Items)
                itemsNames.Add(item.Name);


            // check if there are more listview items than data.
            if (itemsNames.Count > playersNames.Count)
                foreach (var name in itemsNames.Except(playersNames))
                    listView1.Items.RemoveByKey(name);

            listView1.EndUpdate();
        }

我假设engine.enemy[i].name 对于每个玩家来说都是唯一的。

可能代码有一些错误,因为我很久没有为winforms写任何东西了,但我认为你应该明白其中的意思。

【讨论】:

    【解决方案2】:

    是的,您可以使用索引器直接引用您要更新的项目。例如:

    listView2.Items[playerIndex] = new ListViewItem(arr);
    

    至于相对于您的游戏引擎来实现这一点,您需要使用 Reconciliation Design Pattern,它涉及以下给定的游戏引擎列表(Master)和列表视图(Target):

    1. 在 Target 中创建临时项目或键。将此称为 ToDelete。
    2. 单步执行 Master,添加任何不在 Target 中的条目,更新那些在 Target 中的条目。从 ToDelete 中删除与 Target 的每个匹配项。
    3. 从 Target 中删除 ToDelete 中剩余的所有项目。

    更新:正如 Slai 提到的,如果您不想替换整行,可以通过 SubItems 成员进行更新。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-02-21
      • 1970-01-01
      • 2021-11-30
      • 2022-11-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多