-3

I've created a button which is linked to the following function:

 private void btnSetVal_Click_1(object sender, RoutedEventArgs e)
        {
            //VolumeMeter.Value = Convert.ToInt32(txtValue.Text);

           int l_iMilSecs = 1000;
           VolumeMeter.fSetVal(20);
           Thread.Sleep(l_iMilSecs);
           VolumeMeter.Value = 30;
           Thread.Sleep(l_iMilSecs);
           VolumeMeter.Value = 40;
           Thread.Sleep(l_iMilSecs);
           VolumeMeter.Value = 50;
           Thread.Sleep(l_iMilSecs);
           VolumeMeter.Value = 60;
        }

The function fSetVal - updates a user control visibility. In run time the btnSetVal_Click_1 put the thread to sleep(as many times I call sleep) but only perform the last call to fSetVal.. I've tried to add the keyword volatile to the function but it doesn't even compile so it's probably not the right way to go.. Any thought how to prevent it?

fSetVal :

public void fSetVal(int p_iNewVal)
        {
            //Amit: Set the first X(p_iNewVal ) rectangles visible.
            int l_iLastVisibleIndex = m_iNumOfRectangles - p_iNewVal -1;

            for (int i = m_iNumOfRectangles - 1; i > l_iLastVisibleIndex; --i)
            {
                unifGridVolumeMeter.Children[i].Visibility  = Visibility.Visible;
            }

            //Amit: Set the rest of the rectangles to invisible:

            for (int i = 0; i <= l_iLastVisibleIndex; i++)
            {
                unifGridVolumeMeter.Children[i].Visibility  = Visibility.Hidden;
            }

        }
Amit Lipman
  • 687
  • 7
  • 19

1 Answers1

1

The problem is that you're sleeping on the UI thread, which means the UI can't update.

Instead, you should use a timer, e.g. a DispatcherTimer to call a method repeatedly (until it's finished).

Alternatively, make your method async and use Task.Delay instead of Thread.Sleep:

private async void btnSetVal_Click_1(object sender, RoutedEventArgs e)
{
    // TODO: Use a loop instead of this repeated code...
    int l_iMilSecs = 1000;
    VolumeMeter.fSetVal(20);
    await Task.Delay(l_iMilSecs);
    VolumeMeter.Value = 30;
    await Task.Delay(l_iMilSecs);
    VolumeMeter.Value = 40;
    await Task.Delay(l_iMilSecs);
    VolumeMeter.Value = 50;
    await Task.Delay(l_iMilSecs);
    VolumeMeter.Value = 60;
}

Another alternative is to make use of the extensive animation support within WPF...

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • This still has DoEvents() alike issues when for instance closing the Form. The Timer is the way to go. – H H Feb 16 '15 at 12:47
  • @Jon why can't it update? I don't understand the work flow, shouldn't it complete the update (complete the function call) and when go to sleep? – Amit Lipman Feb 16 '15 at 12:53
  • 1
    @AmitLipman: No, because it would need to use the UI thread to do the update - and you've blocked the UI thread by telling it to go to sleep. – Jon Skeet Feb 16 '15 at 12:56
  • @JonSkeet Hey thanks first of all! But there is something else going on.. I've changed the sleep to for (int j = 0; j < 1000; j++) { VolumeMeter.fSetVal(j%100); for (int i = 0; i < 100000; i++) { sw.WriteLine(i.ToString()); } } to make it spend time on irrelevant task. and still it doesn't update the GUI only the last call to fsetVal is taking place.. – Amit Lipman Feb 16 '15 at 13:27
  • 1
    @AmitLipman: That's exactly the same problem: you're doing a lot of work on the UI thread, and you'll only see the update when you finish. Don't do that. Either offload the work to a different thread, or use asynchronous IO. – Jon Skeet Feb 16 '15 at 13:56