Home > Software engineering >  How to update UI in separate thread?
How to update UI in separate thread?

Time:07-08

I have a WPF view with grid that have two elements in it, RichText and Progressbar. When I'm loading a lot of text to RichText I want to show a loading process (just an animation) to the user. The main idea to hide Richtext control, show Progressbar, start load text, when it finish show RichText again. The problem is that while I'm updating RichText control I'm blocking UI and Progressbar is freezed. Is there a way to update Progressbar from another thread, maybe some proxyhost?

Thank you.

CodePudding user response:

Is there a way to update Progressbar from another thread

Short answer: No. A control can only be updated on the thread on which it was originally created.

What you can do is to display the ProgressBar in another window that runs on another thread and then close this window when the RichTextBox on the original thread has been updated.

CodePudding user response:

Create a method on your form to update the element you want to update and the use invoke to run it from your thread

like that:

   private void Form1_Load(object sender, EventArgs e)
        {
            Thread _thread = new Thread(() =>
            {
                //do some work
                upDateUiElements();//pass any parameters you want
            });
            _thread.Start();
        }

        public  void upDateUiElements()//input any parameters you need
        {
                BeginInvoke(new MethodInvoker(() =>
                {            
                //update ui elements
                }));           
        }

If you need to invoke it from a different class you can pass your form as an object and then access the method through that object

Like that:

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            OtherClass _class = new OtherClass(this);
            _class.runthread();
        }

        public  void upDateUiElements()//input any parameters you need
        {
            BeginInvoke(new MethodInvoker(() =>
            {
                //update ui elements
            }));
        }
    }

    class OtherClass
    {
        private Form1 _accessForm1;

        public OtherClass(Form1 accessform1)
        {
            _accessForm1 = accessform1;
        }

        public void runthread()
        {
            Thread _thread = new Thread(() =>
            {
                //do some work
                _accessForm1.upDateUiElements();
            });
            _thread.Start();
        }
    }

CodePudding user response:

You can add this to your usings:

using System.Windows.Threading;

For .NET 5/6, that is enough. For .NET framework you must also add a reference to System.Windows.Presentation.dll.

And this type of code will work fine:

private void Button_Click(object sender, RoutedEventArgs e)
{
    // here we're in UI thread
    var max = 100;
    pg.Maximum = max; // pg is a progress bar
    Task.Run(() =>
    {
        // here we're in another thread
        for (var i = 0; i < max; i  )
        {
            Thread.Sleep(100);

            // this needs the System.Windows.Threading using to support lambda expressions
            Dispatcher.BeginInvoke(() =>
            {
                // this will run in UI thread
                pg.Value = i;
            });
        }
    });
}
  • Related