ElementHost Layout Problems

2020-02-11 09:09发布

I have a bunch of ElementHosts that I'm loading onto my form. When this happens, the element hosts all appear with a black background. If I bring another control to front, then close the other control, the ElementHosts are repainted normally. After some googling, I found that if I sub-class ElementHost and do this in the constructor

 using (CreateGraphics()) { }

The ElementHosts are all drawn with good backgrounds....BUT, they take about 300ms per element host to appear on the form...and they appear sequentially...so it's like watching the form getting laid out... I have, of course called SuspendLayout and ResumeLayout manually, but this doesn't change the result.

Is this just Windows Forms integration bugginess? Or is there something I can do about this to make the controls appear correctly and at a reasonable rate?

Thanks.

UPDATE: I am able to reproduce the problem with the very simple code:

    public partial class TestControl2 : UserControl
    {
        public TestControl2()
        {
            InitializeComponent();
        }

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);

        // deferring load with the BackgroundWorker seems to be related to the problem here...
        var bw = new BackgroundWorker();
        bw.DoWork += delegate { Thread.Sleep(2000); };
        bw.RunWorkerCompleted += delegate
        {
            int x = 0;
            int y = 0;
            for (int i = 0; i < 20; i++)
            {
                var control = new Panel();
                control.Width = 200;
                control.Height = 80;
                control.Controls.Add(new ElementHost { Child = new System.Windows.Controls.Label { Content = @"Hello" }, Dock = DockStyle.Left, Size = new System.Drawing.Size(75, 23) });
                control.Controls.Add(new ElementHost { Child = new System.Windows.Controls.Button { Content = @"button" }, Dock = DockStyle.Fill });
                var uc2 = new UserControl();
                uc2.Controls.Add(control);
                control.Dock = DockStyle.Fill;
                uc2.Left = x;
                uc2.Top = y;
                x += control.Width + 10;
                // adding using (uc2.CreateGraphics()) {} fixes the problem but slows down the load so it looks like each UserControl is being added one at a time
                panel1.Controls.Add(uc2);
            }
        };

        bw.RunWorkerAsync();
    }
    }

2条回答
Melony?
2楼-- · 2020-02-11 09:29

Although not being a direct answer to your problem, have you tried to add just one ElementHost (and hence just one WPF UserControl) to your WindowsForm.

You might achieve this if you create a WPF UserControl which aggregates all your individual WPF UserControl. Is this a viable solution for you? t might reduve Or do you have to mix windows forms controls with wpf ones?

查看更多
相关推荐>>
3楼-- · 2020-02-11 09:39

Holy sh*t, I finally got it working. I tried this code from Google (there were a couple of sources.... How do I suspend painting for a control and its children? ...to name one):

    private const int WM_SETREDRAW = 0x000B;

    public static void Suspend(this Control control)
    {
        Message msgSuspendUpdate = Message.Create(control.Handle, WM_SETREDRAW, IntPtr.Zero,
            IntPtr.Zero);

        NativeWindow window = NativeWindow.FromHandle(control.Handle);
        window.DefWndProc(ref msgSuspendUpdate);
    }

    public static void Resume(this Control control)
    {
        var wparam = new IntPtr(1);
        Message msgResumeUpdate = Message.Create(control.Handle, WM_SETREDRAW, wparam,
            IntPtr.Zero);

        NativeWindow window = NativeWindow.FromHandle(control.Handle);
        window.DefWndProc(ref msgResumeUpdate);

        control.Invalidate();
    }

It didn't solve my problem and left me with the black messed up backgrounds...BUT I thought to try adding the following to the Resume method:

      public static void Resume(this Control control)
      {
            control.Visible = false;                
            // existing code above....
            control.Visible = true;
      }

and BAM!!! it works.

查看更多
登录 后发表回答