0

Here's my situation:

I have a WPF application, where I have a method which takes a lot of time to be completed. I don't want to lose UI responsiveness, so I'd like to call that method in another thread. I won't paste here my entire code, because it's too long, instead I wrote this short program, which represents well what I'm dealing with:

    public void MainWindow()
    {
        InitializeComponent();

        ProcessThread = new Thread(TimeConsumingMethod);
        ProcessThread.Name = "ProcessThread";
        ProcessThread.Start();

    }


    public void TimeConsumingMethod()
    {
        this.Dispatcher.Invoke(() =>
        {
            MytextBlock.Text = "new text";
            MyOtherTextBlock.Text = "Hello";
        });

        for (int i = 0; i < 50; i++)
        {
            Debug.WriteLine("Debug line " + i);
        }


        if (MyRadioButton.IsChecked == false)   //????????????????
        {
            while (true)
            {
                if (DateTime.Now >= timePicker.Value)
                    break;
            }
        }

        OtherMethod();

    }

Actually, I have two questions for the above code: 1. Everytime I want to access UI controls in my code I have to use this.Dispatcher.Invoke() =>.... Is it the right thing to do? I mean, I have a few places in my method (in my real code) where I check the state of some controls and everytime I need to do his Dispatcher.invoke thing - isn't there a better way to acces these controls? 2. In the code above, there's IF block in the end - in that block I'm checking the state of my RadioButton. Inside of that IF, I have a time consuming code. I cannot just do this:

    this.Dispatcher.Invoke(() =>
    {
        if (MyRadioButton.IsChecked == false)   //????????????????
        {
            while (true)
            {
                if (DateTime.Now >= timePicker.Value)
                    break;
            }
        }
    });

That code would tell my UI thread to handle this if block - but I don't want that! That would cause the whole UI to freeze until this IF block gets done. How should I handle this situation?

mnj
  • 2,539
  • 3
  • 29
  • 58
  • What kind of time consuming operation you have? Are you waiting some information from Db/Web or you are doing some CPU intense calculations? – 3615 Sep 05 '16 at 13:25
  • i have 2 time consuming places in my code: 1. Waiting for a specific time to continue calculations. (just like in an example I gave) 2. OtherMethod() which collects informaion about computer's performance (CPU %, RAM, etc.) for as long as the user wants and then saves it in a file – mnj Sep 05 '16 at 13:27

1 Answers1

0

Well, there are a lot of ways to implement what you are trying to do. One of them might look like this:

    public MainWindow() {
        InitializeComponent();
        Initialize(); //do some intialization
    }

    private async void Timer_Tick(object sender, EventArgs e) {
        if (DateTime.Now >= timePicker.SelectedDate) { //check your condition
            timer.Stop(); //probably you need to run it just once

            await Task.Run(() => OtherMethod()); //instead of creating thread manually use Thread from ThreadPool
            //use async method to avoid blocking UI during long method is running
        }
    }

    private readonly DispatcherTimer timer = new DispatcherTimer(); //create a dispatcher timer that will execute code on UI thread

    public void Initialize() {
        MytextBlock.Text = "new text";
        MyOtherTextBlock.Text = "Hello"; //access UI elements normally

        for (var i = 0; i < 50; i++) {
            Debug.WriteLine("Debug line " + i);
        }

        if (MyRadioButton.IsChecked == false)
        {
            timer.Interval = TimeSpan.FromSeconds(10); // during init setup timer instead of while loop
            timer.IsEnabled = true;
            timer.Tick += Timer_Tick; //when 10 sec pass, this method is called
            timer.Start();
        }
    }

    public void OtherMethod() {
        //long running method
        Thread.Sleep(1000);
    }

I've added some comments, but the main idea is this:

  1. Don't create threads manually, use ThreadPool

  2. Don't loop to wait for something, use timer to periodically check for it

  3. Use async method when you have I/O Tasks

3615
  • 3,787
  • 3
  • 20
  • 35
  • what's wrong with using loop (like in my example) to wait for the set time? – mnj Sep 06 '16 at 10:53
  • At least you should put your thread to sleep in the loop, otherwise you will consume tons of CPU time. Timer is created exactly for what you are doing and it makes code more explicit. Check [this](http://stackoverflow.com/q/2822441/5246145) question to get more opinions on that. – 3615 Sep 06 '16 at 11:11