Soru Güncellemede c # titrek Liste görünümü


Periyodik olarak güncellenen bir liste görünümüm var (her 60 saniyede). Her seferinde bir titreme alacağımı anımsatıyordu. Kullanılan yöntem tüm öğeleri temizlemek ve daha sonra onları yeniden oluşturmaktı. Yeni metinle doğrudan hücreye yazacağım eşyaları temizlemek yerine karar verdim. Bu daha iyi bir yaklaşım mı yoksa herkesin daha iyi bir çözümü var mı?


44
2018-01-14 12:44


Menşei




Cevaplar:


ListView denetiminde titreme var. Sorun, denetimin Güncelleme aşırı yükünün, Yenileme gibi davranacak şekilde düzgün şekilde uygulanmadığı gibi görünüyor. Bir Güncelleme, denetimin yalnızca geçersiz bölgelerini yeniden çizmesine neden olurken, Yenile, kontrolün tüm istemci alanını yeniden çizer. Yani, eğer listedeki bir maddenin arka plan rengini değiştirecekseniz, o zaman sadece o özel maddenin yeniden boyanması gerekir. Ne yazık ki, ListView kontrolü farklı bir düşünceye sahip gibi görünüyor ve tek bir öğe ile karıştığında tüm yüzeyini yeniden boyamak istiyor… öğe şu anda görüntülenmiyor olsa bile. Yani, neyse, kolayca aşağıdaki gibi kendi rulo yuvarlayarak titremesini bastırabilirsiniz:

class ListViewNF : System.Windows.Forms.ListView
{
    public ListViewNF()
    {
        //Activate double buffering
        this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);

        //Enable the OnNotifyMessage event so we get a chance to filter out 
        // Windows messages before they get to the form's WndProc
        this.SetStyle(ControlStyles.EnableNotifyMessage, true);
    }

    protected override void OnNotifyMessage(Message m)
    {
        //Filter out the WM_ERASEBKGND message
        if(m.Msg != 0x14)
        {
            base.OnNotifyMessage(m);
        }
    }
}

Gönderen: Geekswithblogs.net


78
2018-01-14 12:47



Bu çözümün dezavantajının (çift tamponlama nedeniyle) kontrolün güncellenmesinin önemli ölçüde daha yavaş olduğunu bilmelisiniz (1000 ürün eklemeyi deneyin). - Sandor Drieënhuizen
Dürüst olmak gerekirse, winforms liste görünümünü asla kullanmıyorum. Ama aradığınızda o perfomance kaybı yok SuspendLayout ve ResumeLayout? - Stormenet
Teşekkürler Stormenent. Bir süredir bu konuya bir çözüm arıyordum ve bu benim için iyi çalışıyor.
OptimizedDoubleBuffer düzgün çalışıyor mu. Ancak, base.OnNotifyMessage (m) çağrısını atlamanın hiçbir şekilde yardımcı olmadığını sanmıyorum. Sadece ILSpy ve Control.OnNotifyMessage ile boş bir uygulama olduğunu kontrol ettim. MSDN'den: "Türetilmiş bir sınıfta OnNotifyMessage'ı geçersiz kılarken, temel uygulamanın OnNotifyMessage yöntemini çağırmak gerekli değildir, çünkü ilk uygulama yoktur." Bu yöntem, iletiler işlendiğinde alt sınıflar bildirilebilir. Bu mesajları değiştirmeniz gerekiyorsa, WndProc'u geçersiz kılmanız gerekir mi? - toong
Bu çözümü beğenmezseniz, alt sınıflamadan dolayı, alt sınıflandırma olmadan çok benzerdir: stackoverflow.com/questions/87795/... - prostynick


Diğer cevaplara ek olarak, birçok kontrolün bir [Begin|End]Update() İçeriği düzenlerken titremeyi azaltmak için kullanabileceğiniz yöntem - örneğin:

    listView.BeginUpdate();
    try {
        // listView.Items... (lots of editing)
    } finally {
        listView.EndUpdate();
    }

21
2018-01-14 12:54



+1: Teşekkürler; Bu fark edilebilir bir fark yarattı :-) - Jon Cage
Kocaman teşekkürler! İnterneti yukarı ve aşağı araştırıyorum ve arama sonuçlarının hiçbiri uygulanabilir değil: D - pepoluan
Bunun yardımcı olduğunu ancak titremeyi tamamen ortadan kaldırdığını buldum. - usr


Evet, çift tamponlu hale getirin. Titremeyi azaltacaktır;) http://msdn.microsoft.com/en-us/library/system.windows.forms.listview.doublebuffered.aspx


4
2018-01-14 12:48



-1: Ayarlayamazsınız ListViewDoubleBuffered özelliği (korunur). - Jon Cage
Yorumunuz için -1 'dir, çünkü siz onu yeni bir sınıf türetirseniz, "SetStyle" yöntemi de vardır. Ancak, birisini oylamadan önce araştırmanızı yapmanın yolu, tam olarak nedenini kullanarak cevap vermiş olsanız bile, yorumun hiçbir anlamı yoktur. başparmak havaya - SilverX
Sadece hatırla, SetStyle da korunuyor ... bunu nasıl aramayı başardın? - SilverX
Cevabınızda türetme hakkında hiçbir şey söylemediniz. - Jon Cage


Mükemmel soru ve Stormenent'in cevabı açıktı. İşte C ++ / CLI uygulamaları ile uğraşan herkes için kodunun C ++ portu.

#pragma once

#include "Windows.h" // For WM_ERASEBKGND

using namespace System;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;

public ref class FlickerFreeListView : public ListView
{
public:
    FlickerFreeListView()
    {
        //Activate double buffering
        SetStyle(ControlStyles::OptimizedDoubleBuffer | ControlStyles::AllPaintingInWmPaint, true);

        //Enable the OnNotifyMessage event so we get a chance to filter out 
        // Windows messages before they get to the form's WndProc
        SetStyle(ControlStyles::EnableNotifyMessage, true);
    }

protected:
    virtual  void OnNotifyMessage(Message m) override
    {
        //Filter out the WM_ERASEBKGND message
        if(m.Msg != WM_ERASEBKGND)
        {
            ListView::OnNotifyMessage(m);
        }
    }

};

4
2017-07-15 14:14





Bu yardımcı olabilir, aşağıdaki bileşen .NET 3.5 ile ListView titrek sorunları çözdü

[ToolboxItem(true)]
[ToolboxBitmap(typeof(ListView))]
public class ListViewDoubleBuffered : ListView
{
    public ListViewDoubleBuffered()
    {
        this.DoubleBuffered = true;
    }
}

Ben ListView.Items manipülasyon yaptığım .BeginUpdate () ve .EndUpdate () yöntemleri ile birlikte kullanın.

.NET 4.5'te bile (belki bir güvenlik sorunu) bu özelliğin neden korunmuş olduğunu anlamıyorum.


3
2017-12-17 12:20





En basit çözüm muhtemelen kullanıyor olabilir

       listView.Items.AddRange(listViewItems.ToArray());

yerine

       foreach (ListViewItem listViewItem in listViewItems)
       {
           listView.Items.Add(listViewItem);
       }

Bu yol daha iyi çalışır.


3
2018-05-08 18:22



Bu kadar çözdüğünüz öğeyi ekleyerek tüm GUI'mı engelleme konusunda gerçekten çok fazla sorun yaşadığına çok teşekkür ederim. - Robin B


İşte liste görünümleri vb. Alt sınıflandırma gerektirmeyen bir C # uygulaması için hızlı çözümüm.

DoubleBuffered Property'i form yapıcısında denemek için ayarlamak için yansıma kullanır.

    lvMessages
        .GetType()
        .GetProperty("DoubleBuffered", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)
        .SetValue(lvMessages, true, null);

2
2018-02-22 11:10