Preload a Form in Another Thread

I am trying to preload server form in the constructor of client form, in a separate thread. My reason is that server load is time consuming.

Here's the client form, you can see in the constructor that I am calling Preload(). There's also a button, clicking on it should show the server, which should be fast since the server form is already preloaded:

public partial class Form1 : Form
{
    ServerUser server = null;
    public Form1()
    {
        InitializeComponent();
        Preload();
    }

    public async void Preload()
    {
      await  Task.Run(() =>
            {
                server = new ServerUser();
                server.LoadDocument();
                server.ShowDialog();
            }
        );
    }

    private void button1_Click(object sender, EventArgs e)
    {
        server.Show();
    }
}

Here I try to preload form ServerUser in constructor of Form1 and if I click on button1 Server form show faster

And here's the server form:

public partial class ServerUser : Form
{
    public ServerUser()
    {
        InitializeComponent();
    }
    public void LoadDocument()
    {
        ConfigureSource();
    }

    public void ConfigureSource()
    {
        InvokeUpdateControls();
    }

    public void InvokeUpdateControls()
    {
          UpdateControls();
    }

    private void UpdateControls()
    {
        richTextBox1.Rtf = Resource1.ReferatPPC_Bun___Copy;
    }
}

2 answers

  • answered 2018-01-14 10:41 Murat Can O─×UZHAN

    Send in constructor;

    public partial class ServerUser : Form
    {
    public ServerUser(Form1 form1)
    {
        InitializeComponent();
        form1.Preload();
    }
    public void LoadDocument()
    {
        ConfigureSource();
    }
    
    public void ConfigureSource()
    {
        InvokeUpdateControls();
    }
    
    public void InvokeUpdateControls()
    {
          UpdateControls();
    }
    
    private void UpdateControls()
    {
        richTextBox1.Rtf = Resource1.ReferatPPC_Bun___Copy;
    }
    }
    
    
    
    public partial class Form1 : Form
    {
    ServerUser server = null;
    public Form1()
    {
        InitializeComponent();
        Preload();
    }
    
    public async void Preload()
    {
      await  Task.Run(() =>
            {
                server = new ServerUser();
                server.LoadDocument();
                server.ShowDialog();
            }
        );
    }
    
    private void button1_Click(object sender, EventArgs e)
    {
        server=new ServerUser(this);// or whatever you want
        server.Show();
    }
    }
    

  • answered 2018-01-14 14:02 Alexander Pope

    You need to rethink your design. You should create all forms from the main UI thread, and offload the heavy lifting(non UI stuff) to the background threads. Calling UI methods from background threads results in undefined behavior or exceptions.

    Also, I think you misunderstand what await does. You call Preload() synchronously even though it is an asynchronous method. This means that by the time server.Show(); is called, Server might still be running one of these methods:

    server = new ServerUser(); //you should move this outside of Task.Run()
    server.LoadDocument(); //implement this method using background threads
    server.ShowDialog(); //this will actually throw an exception if called via Task.Run();
    

    From your sample I suppose LoadDocument is the expensive operation. You should rewrite that method to run on a background thread and make ServerUser show a loading screen untill LoadDocument() completes. Make sure that all UI methods from LoadDocument are called via BeginInvoke or proper async/await.