zoukankan      html  css  js  c++  java
  • WinForms painting SuspendLayout, dblBuffer etc

    WinForms painting - SuspendLayout, dblBuffer etc


    from:
    http://discuss.joelonsoftware.com/default.asp?dotnet.12.454272.8

    Hello,

    (Some context... I work on moderately complex WinForms applications, eg many screens, with complex user controls that compose infragistics with common controls etc, plus a fair bit of background processing (mostly via BackgroundWorkers).  I don't use any true custom controls with fully manual painting.)

    I routinely run into problems with rendering, particularly:
    1) slow rendering
    2) rendering process is visible to user.
    3) flicker during appForm resize and other situations.

    My main issue is that I haven't found a way to fully suspend drawing on a Form or User control that will halt all drawing/layout events on all user-controls and child controls?

    DoubleBuffering - seems to only affect the one control and doesn't help with the rendering of children.

    SuspendLayout - doesn't halt painting, only the Layout.

    Any suggestions appreciated.
    Mike Liddell Send private email
    Tuesday, February 20, 2007
     
     
    Play with the SetStyle setting on various controls ( especially DoubleBuffering, AllPaintingInWmPaint and UserPaint ( don't know how well UserPaint will work for you ).

    Play with these settings on your various controls and see how that works.

    Wednesday, February 21, 2007
     
     
    Here is a specific scenario to consider

    The application form has a wizard-like container control that can host multiple pages.  Each page is a rich UserControl with complex and nested child controls.

    The wizard-container is showing the first page (visible, dock-fill), and the second-page is hidden (visible=false, enabled=false, and/or not even in the controls list).
     
    => How would you transition from page1 to page2 to acheive slick rendering.  In particular, the nicest result is probably a short pause (no visual change to page1) while work is done, then 'pop' the new screen is fully rendered.

    => I find this scenario very hard to get right in general and every application that does this sort of thing has to be custom-fiddled to get a nice result.  I often test variations of orderings of Update/Refresh/BringToFront/Hide/Show and the results are often very suprising (eg change one minor ordering and the visual outcome is drastically different).  Sometimes I try manual rendering of the entire control (including all child controls) to back-buffer, but I haven't had any success with that so far.

    How do other people with this scenario?
    Any suggestions appreciated.
    Mike Liddell Send private email
    Wednesday, February 21, 2007
     
     
    > Sometimes I try manual rendering of the entire control (including all child controls) to back-buffer, but I haven't had any success with that so far.

    I don't know what you've done and haven't tried anything like this myself, but here's a guess.

    When a control isn't visible (e.g. when it's hidden behind another) then the standard OnPaint doesn't work, because the associated Graphics region (which paints to the screen) is clipped.

    What you might be wanting to try, therefore, is draw to a non-screen Graphics object, which you can then blit to the screen.

    The example shown in the help for the BufferedGraphics class might help you do that.

    I don't know how to use BufferedGraphics to buffer output from standard controls (I can see how to do it from custom controls). Maybe it means implementing a MyRender method in your form, which constructs a PaintEventArgs using a Graphics instance obtained from a  BufferedGraphics instance, and which invokes the OnPaint method of the various controls in the form (passing your own PaintEventArgs instance to the controls' OnPaint methods).

    FWIW, printing too entails drawing to a non-screen buffer; I've never implemented printing so I don't know whether that works with standard controls (e.g. whether printing persuades them to render to a non-screen Graphics object).

    The above is something along the lines of what you've been trying, but beware that I'm not confident that this is the best or standard way to do it.

    Also I don't know about "BackgroundWorkers": does that slow down rendering? A tiny bit of flicker or shimmer is normal (and so, expected and barely noticeable) at the best of times when a screen is refreshed (e.g when you scroll a multi-line edit box); but not a lot of flicker.
    Christopher Wells Send private email
    Wednesday, February 21, 2007
     
     
    What I wound up doing was to create a user control that 'drew' the child controls as graphics images (bitmaps, lines, rectangles, etc).  Then one of two approaches:

    1. Place the 'real' controls (one at a time) in the normal tab order as the user tranverses the image, redrawing that control to show any changes, or put the 'real' control where the user clicked if not folloing the tab order.

    2. In the situation where only one record would be live, pop-up a dialgo witht ht real controls and redrraw the image when the dialgo was dismissed, showing the changed data.
    stoneyowl
    Thursday, February 22, 2007
     
     
    Some old fashioned Win32 code might help, if you know when you want to turn updates off and then on:

    public void BeginUpdate()
    {
      SendMessage( this.Handle, WM_SETREDRAW, 0, 0);
    }

    public void EndUpdate()
    {
      SendMessage( this.Handle, WM_SETREDRAW, 1, 0);
      Parent.Invalidate(true);
    }
    BillT Send private email
    Thursday, February 22, 2007
     
     
    Oh, and you should also check out following:

    http://www.syncfusion.com/FAQ/WinForms/
    BillT Send private email
    Thursday, February 22, 2007
     
     
    Don't know if you've already run into this, but one thing I realized today is that SuspendLayout only suspends layout for the control it's called on...and _not_ for any of its child controls.  So if you want to SuspendLayout on the control and all its child controls, you have to write a recursive routine to do so.

    Fixing this doesn't solve all the redraw issues, but it can definitely speed things up.
    Kyralessa Send private email
    Thursday, February 22, 2007
     
     
    I use
     this.SetStyle(ControlStyles.UserPaint |
                    ControlStyles.AllPaintingInWmPaint |
                    ControlStyles.OptimizedDoubleBuffer, true);
                this.UpdateStyles();

    after each constructor and then in the load event I say

    this.Visible = true;
    this.Update();

    Doesn't really solve it entirely but relieves the pain. On second opening its relatively ok - not so much visible drawing.  The first call is what takes time and from what I gather you can only work around this perhaps by ngening.

    Also check performace on a release build.  Things might look a little better also if infragistics controls are running out of GAC it might slow you down a touch.

    These 3rd party custom controls carry a penalty one way  or another. I swapped out a combobox I was too lazy to owner draw and the performance change was remarkable.

    All the best
    by10
    Friday, February 23, 2007
     
     

    This topic is archived. No further replies will be accepted.

  • 相关阅读:
    推送注意事项
    如何实现推送
    SVPRogressHUD问题小总结
    Flurry统计库包含出错处理
    python报"TypeError: object of type 'Greenlet' has no len()"
    python运行不报错又无任何结果输出
    python报"IndentationError: unexpected indent"
    windows环境将系统U盘还原
    windows2007环境Python3.5下paramiko模块的安装
    Python基础九--hashlib、hmac模块
  • 原文地址:https://www.cnblogs.com/luoyaoquan/p/2301846.html
Copyright © 2011-2022 走看看