首页 / 知识

关于c#:如何在更新单个ListViewItem的文本时防止ListView闪烁?

2023-04-16 20:42:00

关于c#:如何在更新单个ListViewItem的文本时防止ListView闪烁?

How to prevent flickering in ListView when updating a single ListViewItem's text?

我想要的是更新ListViewItem的文本,而不会看到任何闪烁。

这是我的更新代码(多次调用):

1
2
3
4
listView.BeginUpdate();
listViewItem.SubItems[0].Text = state.ToString();    // update the state
listViewItem.SubItems[1].Text = progress.ToString(); // update the progress
listView.EndUpdate();

我已经看到了一些解决方案,其中涉及覆盖组件的WndProc():

1
2
3
4
5
6
7
8
protected override void WndProc(ref Message m)
{
    if (m.Msg == (int)WM.WM_ERASEBKGND)
    {
        m.Msg = (int)IntPtr.Zero;
    }
    base.WndProc(ref m);
}

他们说这解决了问题,但就我而言,没有。 我相信这是因为我在每个项目上都使用了图标。


可接受的答案是可行的,但是相当冗长,并且仅出于启用双重缓冲而从控件派生(就像其他答案中提到的那样)也有点过头了。但是幸运的是,如果我们愿意,我们可以进行反思,也可以调用内部方法(但请确保您所做的!)。

将这种方法封装到扩展方法中,我们将得到一个很短的类:

1
2
3
4
5
6
7
8
public static class ControlExtensions
{
    public static void DoubleBuffering(this Control control, bool enable)
    {
        var method = typeof(Control).GetMethod("SetStyle", BindingFlags.Instance | BindingFlags.NonPublic);
        method.Invoke(control, new object[] { ControlStyles.OptimizedDoubleBuffer, enable });
    }
}

可以在我们的代码中轻松调用:

1
2
3
InitializeComponent();

myListView.DoubleBuffering(true); //after the InitializeComponent();

所有的闪烁都消失了。

更新资料

我偶然发现了这个问题,由于这个事实,扩展方法应该(也许)更好:

1
2
3
4
5
public static void DoubleBuffered(this Control control, bool enable)
{
    var doubleBufferPropertyInfo = control.GetType().GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic);
    doubleBufferPropertyInfo.SetValue(control, enable, null);
}

为了结束这个问题,这里是一个帮助程序类,当为表单中的每个ListView或任何其他ListView的派生控件加载表单时,应调用该类。感谢" Brian Gillespie"提供的解决方案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
public enum ListViewExtendedStyles
{
    /// <summary>
    /// LVS_EX_GRIDLINES
    /// </summary>
    GridLines = 0x00000001,
    /// <summary>
    /// LVS_EX_SUBITEMIMAGES
    /// </summary>
    SubItemImages = 0x00000002,
    /// <summary>
    /// LVS_EX_CHECKBOXES
    /// </summary>
    CheckBoxes = 0x00000004,
    /// <summary>
    /// LVS_EX_TRACKSELECT
    /// </summary>
    TrackSelect = 0x00000008,
    /// <summary>
    /// LVS_EX_HEADERDRAGDROP
    /// </summary>
    HeaderDragDrop = 0x00000010,
    /// <summary>
    /// LVS_EX_FULLROWSELECT
    /// </summary>
    FullRowSelect = 0x00000020,
    /// <summary>
    /// LVS_EX_ONECLICKACTIVATE
    /// </summary>
    OneClickActivate = 0x00000040,
    /// <summary>
    /// LVS_EX_TWOCLICKACTIVATE
    /// </summary>
    TwoClickActivate = 0x00000080,
    /// <summary>
    /// LVS_EX_FLATSB
    /// </summary>
    FlatsB = 0x00000100,
    /// <summary>
    /// LVS_EX_REGIONAL
    /// </summary>
    Regional = 0x00000200,
    /// <summary>
    /// LVS_EX_INFOTIP
    /// </summary>
    InfoTip = 0x00000400,
    /// <summary>
    /// LVS_EX_UNDERLINEHOT
    /// </summary>
    UnderlineHot = 0x00000800,
    /// <summary>
    /// LVS_EX_UNDERLINECOLD
    /// </summary>
    UnderlineCold = 0x00001000,
    /// <summary>
    /// LVS_EX_MULTIWORKAREAS
    /// </summary>
    MultilWorkAreas = 0x00002000,
    /// <summary>
    /// LVS_EX_LABELTIP
    /// </summary>
    LabelTip = 0x00004000,
    /// <summary>
    /// LVS_EX_BORDERSELECT
    /// </summary>
    BorderSelect = 0x00008000,
    /// <summary>
    /// LVS_EX_DOUBLEBUFFER
    /// </summary>
    DoubleBuffer = 0x00010000,
    /// <summary>
    /// LVS_EX_HIDELABELS
    /// </summary>
    HideLabels = 0x00020000,
    /// <summary>
    /// LVS_EX_SINGLEROW
    /// </summary>
    SingleRow = 0x00040000,
    /// <summary>
    /// LVS_EX_SNAPTOGRID
    /// </summary>
    SnapToGrid = 0x00080000,
    /// <summary>
    /// LVS_EX_SIMPLESELECT
    /// </summary>
    SimpleSelect = 0x00100000
}

public enum ListViewMessages
{
    First = 0x1000,
    SetExtendedStyle = (First + 54),
    GetExtendedStyle = (First + 55),
}

/// <summary>
/// Contains helper methods to change extended styles on ListView, including enabling double buffering.
/// Based on Giovanni Montrone's article on <see cref="http://www.codeproject.com/KB/list/listviewxp.aspx"/>
/// </summary>
public class ListViewHelper
{
    private ListViewHelper()
    {
    }

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern int SendMessage(IntPtr handle, int messg, int wparam, int lparam);

    public static void SetExtendedStyle(Control control, ListViewExtendedStyles exStyle)
    {
        ListViewExtendedStyles styles;
        styles = (ListViewExtendedStyles)SendMessage(control.Handle, (int)ListViewMessages.GetExtendedStyle, 0, 0);
        styles |= exStyle;
        SendMessage(control.Handle, (int)ListViewMessages.SetExtendedStyle, 0, (int)styles);
    }

    public static void EnableDoubleBuffer(Control control)
    {
        ListViewExtendedStyles styles;
        // read current style
        styles = (ListViewExtendedStyles)SendMessage(control.Handle, (int)ListViewMessages.GetExtendedStyle, 0, 0);
        // enable double buffer and border select
        styles |= ListViewExtendedStyles.DoubleBuffer | ListViewExtendedStyles.BorderSelect;
        // write new style
        SendMessage(control.Handle, (int)ListViewMessages.SetExtendedStyle, 0, (int)styles);
    }
    public static void DisableDoubleBuffer(Control control)
    {
        ListViewExtendedStyles styles;
        // read current style
        styles = (ListViewExtendedStyles)SendMessage(control.Handle, (int)ListViewMessages.GetExtendedStyle, 0, 0);
        // disable double buffer and border select
        styles -= styles & ListViewExtendedStyles.DoubleBuffer;
        styles -= styles & ListViewExtendedStyles.BorderSelect;
        // write new style
        SendMessage(control.Handle, (int)ListViewMessages.SetExtendedStyle, 0, (int)styles);
    }
}


CommonControls 6(XP或更高版本)中的ListView支持双缓冲。幸运的是,.NET将最新的CommonControl包装在系统上。若要启用双重缓冲,请将适当的Windows消息发送到ListView控件。

详细信息如下:
http://www.codeproject.com/KB/list/listviewxp.aspx


在.NET Winforms 2.0中,存在一个称为DoubleBuffered的受保护属性。

通过从ListView继承,可以将此受保护的属性设置为true。这将启用双重缓冲,而无需调用SendMessage。

设置DoubleBuffered属性与设置以下样式相同:

1
listview.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);

http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=94096


我知道这个问题已经很久了,但是因为这是Google上的第一批搜索结果之一,所以我想分享我的修正。

我可以消除100%闪烁的唯一方法是将Oliver(扩展类具有双缓冲)的答案与BeignUpdate()EndUpdate()方法结合使用。

靠它们自己都无法解决我的闪烁问题。
当然,我使用了一个非常复杂的列表,我需要将其推入列表,并且几乎每秒钟都要对其进行更新。


这将有助于:

1
2
3
4
5
6
7
8
class DoubleBufferedListView : System.Windows.Forms.ListView
{
    public DoubleBufferedListView()
        :base()
    {
        this.DoubleBuffered = true;
    }
}


简单的解决方案是这样的:

yourlistview.BeginUpdate()

//对列表中的添加和删除项目进行更新

yourlistview.EndUpdate()


在设置任何列表视图项目之前,请在ListView上调用BeginUpdate()方法,然后仅在添加所有项目之后才调用EndUpdate()。

这样可以停止闪烁。


这是在黑暗中拍摄的照片,但是您可以尝试对控件进行双重缓冲。

1
2
3
4
SetStyle(
  ControlStyles.AllPaintingInWmPaint |
  ControlStyles.UserPaint |
  ControlStyles.DoubleBuffer, true)

如果您只想更新文本,只需直接设置更改后的SubItem的文本,而不是更新整个ListViewItem(您尚未说明更新的方式)。

您显示的覆盖等效于简单地覆盖OnPaintBackground,这将是一种"更正确"的托管方式来执行该任务,并且对单个项目无济于事。

如果您仍然有问题,我们将需要澄清您实际尝试过的操作。


文本闪烁更新的是

最新内容

相关内容

猜你喜欢