Yield() function in PowerBuilder similar

mach_9

Member
Joined
May 24, 2016
Messages
20
Programming Experience
5-10
I have a PowerBuilder app. and the code calls PB function Yield() - "Yields control to other graphic objects, including objects that are not PowerBuilder objects. Yield checks the message queue and if there are messages in the queue, it pulls them from the queue.", is there something similar in C#?

Thank you.
 
It sounds like you're looking for Application.DoEvents. That's the poor man's method of keeping the UI responsive while performing long-running work. There are generally better options though. What are you doing that you think you need it? We may be able to offer a better solution, e.g. use of a BackgroundWorker.
 
A bit of a background, I'm reverse engineering a PB app. to C# windows desktop. I'm not familiar with C#.NET windows forms and trying to mimic the same PB functionality in C#.
In this particular case, the PB app. runs on two machines to process certain data, with each machine having a counter/timer, machine 1 executes at the 0 mark and machine 2 executes at the 30 second mark(60 seconds interval before it will execute on its mark).

I have found a .NET timer but as far as I know you cannot set the interval to start at a certain time, in this case seconds. It would work perfectly on one machine but with two machines executing the code at the same time would cause problems, that is why the offset marks are at 0 and 30 with 60 seconds interval.

PB code uses a DO UNTIL loop which I have recreated in C#.
PB code:
C#:
//Counter event:
gi_offset = //Global variable set at the application open event, equivalent to program.cs - main event. Will be 0 or 30 depending on the machine.
li_difference = Integer( String( Now(), 'ss')) //Gets the seconds from the current date time.
DO UNTIL li_difference = gi_offset
 
 ls_status = 'current second: ' + String( Now(), 'ss') + ' starting on:' + String( gi_offset)// Builds a string to display in a static text control in PB, label in C#.
 IF st_status.Text <> ls_status THEN st_status.Text = ls_status
 
 Yield()
 
 li_difference = Integer( String( Now(), 'ss'))
LOOP
//execute main processing method.
ue_process_records.
//End of event
After ue_process_records has completed processing, it will go back to the counter event and start all over.

-In PB, while the window is open all controls are visible and accessible with the counter displaying in the ST control until the difference equals the offset, then it will fire the main processing method. This also displays the count down 0,1,2,...etc.... until it hits 0 or 30.

I've googled it to you know what and have found 'Shown += Form1_Shown;' which will fire at the end according to the MSDN site but I have tried in the form load and cannot get the window to stay open as it seems it is processing.

My code:
private void Form1_Shown(Object sender, EventArgs e)
        {
            ue_wait();
        }
private void wf_actions_Load(object sender, EventArgs e)
        {
            //Should fire after all of the form has loaded.           
            Shown += Form1_Shown;
        }
 
private void ue_wait()
        {
            long todays_date_in_seconds = DateTime.Now.Second;
            long ll_global_offset = 0;
            string ls_status = "";
            
            todays_date_in_seconds = DateTime.Now.Second;
            while (!(todays_date_in_seconds == ll_global_offset))
            {
                ls_status = "Current second: " + DateTime.Now.Second.ToString() + " starting on: " + ll_global_offset.ToString();
                lbl_status.Text = ls_status;
                todays_date_in_seconds = DateTime.Now.Second;
            }

            ue_action();
      
        }
private void ue_action()
        {
            //For testing purposes I want it to call ue_wait and see if the window will stay open to be able to see the counter, but I am not able to view the window in its enabled state.
            ue_wait();
        }

Since I don't have something similar to the Yield() in my C# code, thought it might be that.

Any help is much appreciated.

Thank you,

William
 
Last edited by a moderator:
So I have tried the two possibilities that I found on the Inet:

this.Shown += new System.EventHandler(this.Form1_Shown);
this.Activated += AfterLoading;

However when calling ue_action I get the error below in the ue_wait event for both...

{Cannot evaluate expression because the current thread is in a stack overflow state.}

Fails on the first line: long todays_date_in_seconds = DateTime.Now.Second;

Not sure how to fix this, maybe the Yield() will work...

Thanks
 
I have found a .NET timer but as far as I know you cannot set the interval to start at a certain time, in this case seconds.

Of course you can. You simply subtract the current time from the target time, convert the result into milliseconds and assign that to the Interval of your Timer. The Timer will then raise its event at the desired time, give or take a few milliseconds.
 
My apologies if I wasn't clear or maybe I'm misunderstanding something, but what I would be looking for in the timer, with the Timer.Start(), machine # 1, I would like it to start on the 0 second mark: Timer.Start(0) or Timer.Start() = 0, machine # 2, and I would like it to start on the 30 second mark: Timer.Start(30000) or Timer.Start() = 30000 and each timer execute every 60 seconds on that mark. I understand that I can set the Interval = 60000 for every 60 seconds.

The Timer.Start() does not take any parameters and you are not able to set it to my understanding.

Thanks
 
The rather salient point that you're missing is that you can change the Interval of a Timer. If you want a Timer to Tick after 30 seconds and then every 60 seconds after that the you set the Interval to 30000, Start the Timer and then set the Interval to 60000 when it Ticks. Look at this very simple example:
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            textBox1.AppendText($"Start: {DateTime.Now.ToLongTimeString()}\r\n");

            tickTimer.Interval = 5000;
            tickTimer.Start();

            tockTimer.Interval = 10000;
            tockTimer.Start();
        }

        private void tickTimer_Tick(object sender, EventArgs e)
        {
            tickTimer.Interval = 10000;

            textBox1.AppendText($"Tick: {DateTime.Now.ToLongTimeString()}\r\n");
        }

        private void tockTimer_Tick(object sender, EventArgs e)
        {
            textBox1.AppendText($"Tock: {DateTime.Now.ToLongTimeString()}\r\n");
        }
    }
 
I figured it out, I set the Tick Event to 1 second intervals and when it meets the offset second which is set in PageLoad and stored as an instance variable, will execute the main method

PageLoad event
-set offset instance variable.

ue_action
-set instance Boolean to true after processing is successful.

private void timer1_Tick(object sender, EventArgs e)
{
string ls_status = "";

var currentSecond = DateTime.Now.Second;

ls_status = "Current second: " + currentSecond.ToString() + " starting on: " + Il_offset.ToString();

lbl_status.Text = ls_status;

if (currentSecond == Il_offset && Ib_processing_completed)
{
//Executes main method
ue_action();

}
}

Thank you for all your help, much appreciated.
 
I figured it out, I set the Tick Event to 1 second intervals and when it meets the offset second which is set in PageLoad and stored as an instance variable, will execute the main method

That is an inferior solution, but it's your prerogative to use an inferior solution if you want to.
 
Back
Top Bottom