pengembangan-web-mp-pd.com

Bagaimana mencegah kerlipan di ListView saat memperbarui satu teks ListViewItem?

Yang saya inginkan adalah memperbarui teks ListViewItem tanpa melihat adanya kelipan.

Ini adalah kode saya untuk memperbarui (dipanggil beberapa kali):

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

Saya telah melihat beberapa solusi yang melibatkan penggantian WndProc(): komponen

protected override void WndProc(ref Message m)
{
    if (m.Msg == (int)WM.WM_ERASEBKGND)
    {
        m.Msg = (int)IntPtr.Zero;
    }
    base.WndProc(ref m);
}

Mereka mengatakan itu memecahkan masalah, tetapi dalam kasus saya Itu tidak . Saya percaya ini karena saya menggunakan ikon pada setiap item.

46
Jonas

Untuk mengakhiri pertanyaan ini, berikut adalah kelas pembantu yang harus dipanggil saat formulir memuat untuk setiap ListView atau kontrol lain yang diturunkan ListView dalam formulir Anda. Terima kasih kepada "Brian Gillespie" karena memberikan solusinya.

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

Jawaban yang diterima berfungsi, tetapi cukup panjang, dan berasal dari kontrol (seperti yang disebutkan dalam jawaban lain) hanya untuk mengaktifkan buffering ganda juga agak berlebihan. Tetapi untungnya kami memiliki refleksi dan juga dapat memanggil metode internal jika kami mau (tapi pastikan apa yang Anda lakukan!).

Jadilah merangkum pendekatan ini menjadi metode ekstensi, kita akan mendapatkan kelas yang cukup singkat:

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

Yang dapat dengan mudah dipanggil dalam kode kami:

InitializeComponent();

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

Dan semua kerlip hilang.

Memperbarui

Saya menemukan pertanyaan ini dan karena fakta ini, metode ekstensi seharusnya (mungkin) lebih baik:

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

ListView in CommonControls 6 (XP atau yang lebih baru) mendukung buffering ganda. Untungnya, .NET membungkus CommonControls terbaru pada sistem. Untuk mengaktifkan buffering ganda, kirim pesan Windows yang sesuai ke kontrol ListView.

Berikut detailnya: http://www.codeproject.com/KB/list/listviewxp.aspx

11
Brian Gillespie

Di .NET Winforms 2.0 terdapat properti yang dilindungi yang disebut DoubleBuffered.

Dengan mewarisi dari ListView, maka seseorang dapat mengatur properti yang dilindungi ini menjadi true. Ini akan mengaktifkan buffering ganda tanpa perlu memanggil SendMessage.

Mengatur properti DoubleBuffered sama dengan mengatur gaya berikut:

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

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

10
Rolf Kristensen

Saya tahu pertanyaan ini cukup lama, tetapi karena ini adalah salah satu hasil pencarian pertama di Google, saya ingin membagikan perbaikan saya.

Satu-satunya cara saya bisa menghapus kedipan 100% adalah dengan menggabungkan jawaban dari Oliver (kelas ekstensi dengan buffering ganda) dan menggunakan metode BeignUpdate() dan EndUpdate().

Tak satu pun dari mereka yang dapat memperbaiki kedipan untuk saya sendiri ... Tentu saja, saya menggunakan daftar yang sangat kompleks, yang saya perlu masukkan ke dalam daftar dan juga perlu memperbaruinya hampir setiap detik.

2
T4cC0re

ini akan membantu:

class DoubleBufferedListView : System.Windows.Forms.ListView
{
    public DoubleBufferedListView()
        :base()
    {
        this.DoubleBuffered = true;
    }
}
1
Bjoern

Jika Anda hanya ingin memperbarui teks, cukup atur teks SubItem yang diubah secara langsung daripada memperbarui seluruh ListViewItem (Anda belum mengatakan bagaimana Anda melakukan pembaruan).

Override yang Anda tampilkan setara dengan hanya meng-override OnPaintBackground, yang akan menjadi cara yang dikelola lebih "benar" untuk melakukan tugas itu, dan itu tidak akan membantu untuk satu item.

Jika Anda masih memiliki masalah, kami perlu klarifikasi tentang apa yang sebenarnya Anda coba.

0
ctacke

Ini adalah bidikan dalam gelap, tetapi Anda dapat mencoba menggandakan kontrol.

SetStyle(
  ControlStyles.AllPaintingInWmPaint |
  ControlStyles.UserPaint |
  ControlStyles.DoubleBuffer, true)
0
Ed S.

Panggil metode BeginUpdate () pada ListView sebelum mengatur salah satu item tampilan daftar dan kemudian hanya memanggil EndUpdate () setelah semua item telah ditambahkan.

Itu akan menghentikan flicker.

0
Mike

Solusi sederhana adalah ini:

yourlistview.BeginUpdate ()

// Lakukan pembaruan Anda untuk menambah dan menghapus item dari daftar

yourlistview.EndUpdate ()

0
jaiveeru