Het flikkeren in Gebruikersbedieningen oplossen

In mijn applicatie ga ik constant van het ene besturingselement naar het andere. Ik heb nr gemaakt. gebruikersbedieningen, maar tijdens het navigeren flikkeren mijn bedieningselementen. het duurt 1 of 2 seconden om te updaten. Ik heb geprobeerd dit in te stellen

SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
or
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true); 
SetStyle(ControlStyles.DoubleBuffer, true);

maar het heeft niet geholpen… Elk besturingselement heeft dezelfde achtergrondafbeelding met verschillende besturingselementen.
Dus wat is de oplossing ervoor..

Bedankt.


Antwoord 1, autoriteit 100%

Het is niet het soort flikkering dat dubbele buffering kan oplossen. Noch BeginUpdate of SuspendLayout. Je hebt te veel bedieningselementen, de BackgroundImage kan het veelerger maken.

Het begint wanneer de UserControl zichzelf schildert. Het tekent de BackgroundImage en laat gaten achter waar de child control-vensters gaan. Elk kinderbesturingselement krijgt dan een bericht om zichzelf te schilderen, ze vullen het gat met hun vensterinhoud. Wanneer je veel bedieningselementen hebt, zijn die gaten een tijdje zichtbaar voor de gebruiker. Ze zijn normaal gesproken wit en contrasteren slecht met de BackgroundImage als het donker is. Of ze kunnen zwart zijn als het formulier de eigenschap Opacity of TransparencyKey heeft ingesteld, wat een slecht contrast vormt met zo ongeveer alles.

Dit is een vrij fundamentele beperking van Windows Forms, het zit vast in de manier waarop Windows vensters weergeeft. Opgelost door WPF btw, het gebruikt geen vensters voor kinderbesturing. Wat je zou willen, is het hele formulier dubbel bufferen, inclusief de onderliggende besturingselementen. Dat kan, bekijk mijn code in deze draadvoor de oplossing. Het heeft echter bijwerkingen en verhoogt de schildersnelheid niet echt. De code is eenvoudig, plak deze in je formulier (niet de gebruikerscontrole):

protected override CreateParams CreateParams {
  get {
    CreateParams cp = base.CreateParams;
    cp.ExStyle |= 0x02000000;  // Turn on WS_EX_COMPOSITED
    return cp;
  }
} 

Er zijn veel dingen die u kunt doen om de schildersnelheid te verbeteren, tot het punt dat de flikkering niet meer waarneembaar is. Begin met het aanpakken van de BackgroundImage. Ze kunnen echtduur zijn als de bronafbeelding groot is en moet worden verkleind om in het besturingselement te passen. Wijzig de eigenschap BackgroundImageLayout in “Tegel”. Als dat een merkbare snelheidswinst oplevert, gaat u terug naar uw tekenprogramma en wijzigt u het formaat van de afbeelding zodat deze beter overeenkomt met de typische controlegrootte. Of schrijf code in de OnResize()-methode van de UC om een ​​kopie van de afbeelding met de juiste grootte te maken, zodat het formaat niet telkens opnieuw hoeft te worden gewijzigd als het besturingselement opnieuw wordt geverfd. Gebruik het Format32bppPArgb pixelformaat voor die kopie, het rendert ongeveer 10 keer sneller dan enig ander pixelformaat.

Het volgende dat u kunt doen, is voorkomen dat de gaten zo opvallen en slecht contrasteren met de afbeelding. U kunt uitschakelende WS_CLIPCHILDREN-stijlvlag voor de UC, de vlag die verhindert dat de UC schildert in het gebied waar de onderliggende bedieningselementen komen. Plak deze code in de UserControl-code:

protected override CreateParams CreateParams {
  get {
    var parms = base.CreateParams;
    parms.Style &= ~0x02000000;  // Turn off WS_CLIPCHILDREN
    return parms;
  }
}

De onderliggende besturingen schilderen zichzelf nu bovenop de achtergrondafbeelding. Je ziet ze misschien nog steeds een voor een schilderen, maar het lelijke tussenliggende witte of zwarte gat is niet zichtbaar.

Last but not least is het verminderen van het aantal onderliggende besturingen altijd een goede manier om problemen met langzaam schilderen op te lossen. Negeer de OnPaint()-gebeurtenis van de UC en teken wat nu in een kind wordt getoond. Bijzonder Label en PictureBox zijn ergverspillend. Handig voor aanwijzen en klikken, maar hun lichtgewicht alternatief (een tekenreeks of een afbeelding tekenen) vereist slechts een enkele regel code in uw OnPaint()-methode.


Antwoord 2, autoriteit 3%

Dit is een reëel probleem, en het antwoord dat Hans Passant gaf is geweldig om de flikkering op te slaan. Er zijn echter bijwerkingen zoals hij al zei, en ze kunnen lelijk zijn (UI lelijk). Zoals vermeld: “Je kunt de WS_CLIPCHILDREN-stijlvlag voor de UC uitschakelen”, maar dat schakelt het alleen uit voor een UC. De componenten op het hoofdformulier hebben nog steeds problemen.

Een voorbeeld: een schuifbalk van een paneel wordt niet weergegeven, omdat deze zich technisch in het onderliggende gebied bevindt. De onderliggende component tekent echter niet de schuifbalk, dus deze wordt pas overgeschilderd als de muis eroverheen gaat (of een andere gebeurtenis deze activeert).

Ook geanimeerde pictogrammen (pictogrammen wijzigen in een wachtlus) werken niet. Als u pictogrammen op een tabPage.ImageKeyverwijdert, wordt het formaat van de andere tabbladen niet aangepast.

Dus ik was op zoek naar een manier om de WS_CLIPCHILDRENbij het eerste schilderen uit te schakelen, zodat mijn formulier mooi geverfd wordt, of beter nog, het alleen aanzet terwijl ik het formaat van mijn formulier met veel componenten aanpas.

De truc is om de applicatie CreateParamste laten aanroepen met de gewenste WS_EX_COMPOSITED/WS_CLIPCHILDRENstijl. Ik heb hier een hack gevonden (https://web.archive.org/web/20161026205944/http://www.angryhacker.com/blog/ archive/2010/07/21/hoe-te-ontdoen-van-flicker-on-windows-forms-applications.aspx) en het werkt geweldig. Bedankt AngryHacker!

Ik plaats de TurnOnFormLevelDoubleBuffering()aanroep in de vorm ResizeBegingebeurtenis en TurnOffFormLevelDoubleBuffering()aanroep in de vorm ResizeEnd gebeurtenis (of laat it WS_CLIPCHILDRENnadat het in eerste instantie correct is geverfd.)

   int originalExStyle = -1;
    bool enableFormLevelDoubleBuffering = true;
    protected override CreateParams CreateParams
    {
        get
        {
            if (originalExStyle == -1)
                originalExStyle = base.CreateParams.ExStyle;
            CreateParams cp = base.CreateParams;
            if (enableFormLevelDoubleBuffering)
                cp.ExStyle |= 0x02000000;   // WS_EX_COMPOSITED
            else
                cp.ExStyle = originalExStyle;
            return cp;
        }
    }
    public void TurnOffFormLevelDoubleBuffering()
    {
        enableFormLevelDoubleBuffering = false;
        this.MaximizeBox = true;
    }

Antwoord 3, autoriteit 2%

Als je een aangepast schilderij aan het maken bent in de besturing (d.w.z. OnPaint overschrijven), kun je zelf de dubbele buffering proberen.

Image image;
protected override OnPaint(...) {
    if (image == null || needRepaint) {
        image = new Bitmap(Width, Height);
        using (Graphics g = Graphics.FromImage(image)) {
            // do any painting in image instead of control
        }
        needRepaint = false;
    }
    e.Graphics.DrawImage(image, 0, 0);
}

En maak uw controle ongeldig met een eigenschap NeedRepaint

Anders is het bovenstaande antwoord met SuspendLayout en ResumeLayout waarschijnlijk wat je zoekt.


Antwoord 4

Heb je Control.DoubleBufferedeigenschap?

Krijgt of stelt een waarde in die aangeeft of dit besturingselement het oppervlak opnieuw moet tekenen met een secundaire buffer om flikkering te verminderen of te voorkomen.

Ook diten ditkan helpen.


Antwoord 5

Er is geen dubbele buffering nodig en dat soort dingen jongens…

Een eenvoudige oplossing…

Als u de MDI-interface gebruikt, plakt u de onderstaande code in het hoofdformulier. Het zal alle flikkeringen van de pagina’s verwijderen. Sommige pagina’s die meer tijd nodig hebben om te laden, worden echter binnen 1 of 2 seconden weergegeven. Maar dit is beter dan een flikkerende pagina te tonen waarin elk item één voor één komt.

Dit is de enige beste oplossing voor de hele applicatie. Zie de code om in het hoofdformulier te zetten:

protected override CreateParams CreateParams {
  get {
    CreateParams cp = base.CreateParams;
    cp.ExStyle |= 0x02000000;  // Turn on WS_EX_COMPOSITED
    return cp;
  }
} 

Other episodes