0

I want to assign a new thread to a continuous Progress-bar in WPF application, so that it will run continuously after clicking on UI button till I receive the service response.

I did a code like below, but progress-bar (MclarenServerCecksProgressBar) it seems not working at all

MclarenServerCecksProgressBar.Visibility = Visibility.Visible;
var uiThread = new Thread(() =>
{
progressBarDisptacher = MclarenServerCecksProgressBar.Dispatcher;


// allowing the main UI thread to proceed 
System.Windows.Threading.Dispatcher.Run();    
});
uiThread.SetApartmentState(ApartmentState.STA);
uiThread.IsBackground = true;
uiThread.Start();      
string[] servicesss = getServices(servername,server);
DataTable dtd = esd.getListOfServices(servername, usrid.Text.ToString(),   
userpass.Password.ToString(), servicesss);
MclarenServerCecksProgressBar.Visibility = Visibility.Hidden;

Please arrange to suggest me to achieve this, any other pointers will be much helpful.

leppie
  • 115,091
  • 17
  • 196
  • 297
Indranil Sarkar
  • 1,220
  • 1
  • 14
  • 22

3 Answers3

0

I don't get how in your code progressbar value sets. Also I do not quite understand why are you using this hacking with threads. I made an example how I am doing this with progress-bars, if I understand your question right.

<Window x:Class="WpfApplication5.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow"
    Height="350"
    Width="525">
<Grid>
    <ProgressBar Height="10"
             HorizontalAlignment="Left"
             Margin="12,12,0,0"
             Name="progressBar1"
             VerticalAlignment="Top"
             Width="100"
             Visibility="Hidden" />
    <Button Content="Button"
        Height="23"
        HorizontalAlignment="Left"
        Margin="30,54,0,0"
        Name="button1"
        VerticalAlignment="Top"
        Width="75"
        Click="button1_Click" />
</Grid>
</Window>

using System;
using System.Threading;
using System.Windows;

namespace WpfApplication5 {
    public partial class MainWindow : Window {
        public MainWindow() {
            InitializeComponent();
        }

        void button1_Click(object sender, RoutedEventArgs e) {
            progressBar1.Visibility = Visibility.Visible;
            Action method = () => {
                Action<int> method2 = (val) => {
                    progressBar1.Value = val;
                };
                for (int i = 0 ; i < 10 ; i++) {
                    Thread.Sleep(500);
                    Dispatcher.BeginInvoke(method2, i * 10);
                }
                Action method3 = () => {
                    progressBar1.Visibility = Visibility.Hidden;
                };
                Dispatcher.BeginInvoke(method3);
            };
            method.BeginInvoke(null, null);
        }
    }
}
Alex Butenko
  • 3,664
  • 3
  • 35
  • 54
  • Hey I have tried this, but again Progress-Bar is not running..Is this something can be done by BackGroundWorker. Please help Action method = () => { Action method2 = (val) => { MclarenServerCecksProgressBar.Visibility = Visibility.Visible; MclarenServerCecksProgressBar.Value = val; }; for (int i = 0 ; i < 10 ; i++) { Dispatcher.BeginInvoke(method2, i * 10); } }; – Indranil Sarkar Mar 29 '13 at 13:07
  • I don't bother with ProgressBar value I have set the property IsIndeterminate="True" , I want to achieve this by making this visible on the running application, and close that when we complete any operation after calling the function. – Indranil Sarkar Mar 29 '13 at 13:20
  • I copied the code directly from the project, and this example worked correctly. Try to create a new WPF project, and paste my example. If it does not work, let me know. If the example will work, we need more information to understand the context in which your code is. – Alex Butenko Mar 29 '13 at 13:21
  • I didn't read your last comment. If you need to set IsIndeterminate="True", or do whatever you want with interface, you can just make a new Action method, and call it by Dispatcher (Dispatcher.BeginInvoke(method) from any thread, UI or non-UI. – Alex Butenko Mar 29 '13 at 13:30
  • I understood now that what you are saying. Can I ask how do I create a new thread and so that then I'll call Dispatcher.BeginInvoke(method) from the thread. Can you paste a small code for it. I'll be more grateful for your help. – Indranil Sarkar Mar 29 '13 at 15:38
  • method.BeginInvoke() in my code do that. BeginInvoke starts a new thread, in which method is executed. – Alex Butenko Mar 29 '13 at 15:53
0

Finaly I have achieved this by doing some trick. I have used delegate with DependencyProperty and Dispatacher to update the Progressbar, any way this works for me after a long time with various tries, see the code that I did like below

private delegate void UpdateProgressBarDelegate(
    System.Windows.DependencyProperty dp, Object value);

private void startProgessBar(string controlname)
{
    MclarenServerCecksProgressBar.Visibility = Visibility.Visible;


    //Stores the value of the ProgressBar

    //Create a new instance of our ProgressBar Delegate that points
    // to the ProgressBar's SetValue method.
    UpdateProgressBarDelegate updatePbDelegate =
        new UpdateProgressBarDelegate(MclarenServerCecksProgressBar.SetValue);
    bool _status = true;
    int flag = 0;
    double value = 0;

    do
    {

        /*Update the Value of the ProgressBar: */

        Dispatcher.Invoke(updatePbDelegate,
            System.Windows.Threading.DispatcherPriority.Background,
            new object[] { System.Windows.Controls.ProgressBar.ValueProperty, value });


                if (flag == 0)
                {
                    flag == 1
                    _status = processesServices(controlname);
                }
                if (_status == false)
                {
                    MclarenServerCecksProgressBar.Visibility = Visibility.Hidden;
                }
    }
    while (_status);
}

It might be dirty anyway to fix it that I was looking for running the progessbar till I receive a response from a function, any other suggestion to improve this way would be much appriciated. Welcome for any suggestion and assistance to improve this.

Indranil Sarkar
  • 1,220
  • 1
  • 14
  • 22
0

A WPF UI only ever has one UI thread that you can use for communication - the dispatcher thread. All your background tasks can be done on whatever threads you like, as long as the calls that interact with the UI object are done via the UI dispatcher. Sending calls through this dispatcher is a common task, so the Dispatcher property is provided on each WPF object.

I would approach the problem like this:

    private void button2_Click(object sender, RoutedEventArgs e)
    {
        // Currently running on the WPF thread so the WPF property can be set directly
        this.progressBar1.Visibility = System.Windows.Visibility.Visible;

        // Create a new thread to do the long running task
        Thread worker = new Thread(() =>
        {
            WebService.DoSomethingThatTakesAges();

            // When the above call has completed, update the UI on its dispatcher thread
            this.progressBar1.Dispatcher.BeginInvoke(new Action(() =>
                {
                    this.progressBar1.Visibility = System.Windows.Visibility.Hidden;
                }));
        });

        worker.Start();
    }

It's probably better to use the System.Threading.Tasks namespace to create Tasks with TaskSchedulers rather than create threads directly, but the principle is the same.

Stephen Hewlett
  • 2,415
  • 1
  • 18
  • 31
  • Thanks for your help. Ya I don't need to use dependency property as long as I am not updating ProgreeBar value on UI screen. Can I ask what if I want to do some other operation also on different button click. So then also I need to code like above Thread worker = new Thread(() => {---------} worker.start(); Or we can create this Thread only one time for any WPF form. – Indranil Sarkar Mar 30 '13 at 17:59
  • I just put it in the `button_click` event handler to demonstrate that the code had to be run on the UI thread. It could go anywhere, but if its not run from the UI thread then the first `this.progressBar1.Visibility ...` call will have to be wrapped in a call to `this.progressBar1.Dispatcher.BeginInvoke` like the second one. – Stephen Hewlett Mar 30 '13 at 19:49
  • As it stands at the moment, the thread that is created will run until the web service call is completed and then terminate. You can create a new one to call it again. – Stephen Hewlett Mar 30 '13 at 19:50