【问题标题】:C# ObjectListView flicker on refreshobjectC# ObjectListView 在 refreshobject 上闪烁
【发布时间】:2019-12-11 14:58:10
【问题描述】:

我使用的 ObjectListView 总体上很好,但我发现了一个问题,因为它是一个视觉错误。我有一个方法,它每 2 秒运行一次,并根据条件用当前时间更新一些列。但是在我更新对象并使用 RefreshObject 方法之后,该行在一段时间内获得默认背景颜色并恢复他的行颜色,这会导致闪烁。如果我不执行 RefreshObject ,它会在该行内更新我的模型,但不会在视觉上更新。我得到行项目的方式是这样的:

rowItem GG = OLVa.GetItem(i).RowObject as rowItem;
GG.Time = "something";
OLVa.Refreshobject(GG);

我给行上色的方式是这样的:

OLVa.GetItem(i).BackColor = Color.Pink;

根据条件更改行的背景颜色后,我只使用OLVa.Refresh();

我不确定我在为行着色或更新行时做错了什么?

【问题讨论】:

    标签: c# objectlistview


    【解决方案1】:

    解决您的问题

    问题在于使用返回 UI 控制元素的GetItem。使用对象列表视图,您应该根据对象执行所有操作,而不是更改实际的 Control 元素。基本上,您是在使用这种方法与 API 作斗争,而不是使用它。

    我认为你应该使用RowFormatter来设置背景颜色:

    OLVa.RowFormatter = (o) =>
    {
        if(o.RowObject == "B")
            o.BackColor = Color.Pink;
    };
    

    重现您的问题

    我能够使用以下(错误)代码重现您描述的问题。它会像您描述的那样产生闪烁:

    
    public class MainForm : Form
    {
        public MainForm()
        {
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
            // 
            // MainForm
            // 
            this.ClientSize = new System.Drawing.Size(284, 261);
            this.Name = "MainForm";
            this.ResumeLayout(false);
            this.PerformLayout();
    
            var OLVa = new ObjectListView();
            OLVa.Dock = DockStyle.Fill;
            OLVa.Columns.Add(new OLVColumn("Name", "ToString"));
            this.Controls.Add(OLVa);
    
            OLVa.AddObject("A");
            OLVa.AddObject("B");
            OLVa.AddObject("C");
    
            Timer t = new Timer();
            t.Interval = 100;
            t.Tick += (s,e)=>OLVa.RefreshObject("B");
            t.Start();
    
            Timer t2 = new Timer();
            t2.Interval = 200;
            t2.Tick += (s,e)=>OLVa.GetItem(1).BackColor = Color.Pink;
            t2.Start();
        }
    }
    

    将第二个计时器更改为行格式化程序解决了问题。

    根据条件更改行突出显示

    调用RefreshObject 会自动触发RowFormatter 和方面,因此如果您想随时间更改行的状态(例如,按照您在评论中的要求),您可以执行以下操作:

        public class MainForm : Form
        {
            public MainForm()
            {
                System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
                // 
                // MainForm
                // 
                this.ClientSize = new System.Drawing.Size(300, 300);
                this.Name = "MainForm";
                this.ResumeLayout(false);
                this.PerformLayout();
    
                var OLVa = new FastObjectListView();
                OLVa.Width = 250;
                OLVa.Height = 250;
                OLVa.Columns.Add(new OLVColumn("Done", "Done"));
                OLVa.Columns.Add(new OLVColumn("Percent", "PercentComplete"));
    
                this.Controls.Add(OLVa);
    
                Video v = new Video();
    
                OLVa.AddObject(v);
    
                var t = new Timer();
                t.Interval = 1000;
                t.Start();
    
                OLVa.RowFormatter = (s) => s.BackColor = ((Video) s.RowObject).Done ? Color.Green : Color.Red;
    
                t.Tick += (s,e)=>
                {
                    v.PercentComplete = Math.Min(v.PercentComplete += 10, 100);
                    if (v.PercentComplete == 100)
                        v.Done = true;
    
                    OLVa.RefreshObject(v);
                };
    
            }
    
            private class Video
            {
                public bool Done { get; set; }
                public int PercentComplete { get; set; }
            }
        }
    

    【讨论】:

    • 好的,我已经返回了我正在使用 GetItem 绘制的绘制方法,但现在我的项目颜色没有改变。如果我理解正确,RowFormatter 仅在我添加新项目时第一次工作。 “此委托可用于在将 OLVListItem 添加到控件之前对其进行格式化。”我需要这种方式在某些情况下工作,比如用户交互和其他一些事情,你能帮我怎么做吗?例如,如果我的 objectlistview 中有视频,并且我想在视频完成后重新着色我的项目,我该如何实现?喜欢播放的项目将是红色的,当前的一个绿色,其余的黄色
    • 我已更新答案以显示如何重新着色行。基本上可以归结为只需调用RefreshObject 即可。
    • 使用 ObjectListView,您几乎不想自己绘图(至少不是 Windows 窗体版本)。您设置规则(例如格式化程序、方面 getter 等)然后添加对象,如果对象更改,您调用 RefreshObject。事实上RowFormatter 在其他情况下也会触发(例如,当鼠标进入行时)。最好假设该方法会定期触发(因此不要在其中放置任何昂贵的操作),但如果您知道您的对象状态发生了有意义的变化,请确保调用 RefreshObject
    • 感谢您的尝试,我使用普通 objectlistview 而不是 fastobjectlistview,并且使用 1200 项需要太多时间,而使用子项着色设置开始时间需要 1300-1500 毫秒,这并不完美但可以容忍,但当我切换我的模型以使用 INotifyPropertyChanged 并更新我的开始时间值时,它需要 4000-4700 毫秒。所以我将使用一种混合解决方案,对于我的开始时间(每 2 秒设置一次),我将使用普通列表视图,而对于其他我不会更新太多的事情,我将使用 ObjectListView
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-06
    相关资源
    最近更新 更多