简体   繁体   中英

Update UI after calling external C++ library from C#

I'm building a C# wrapper class library for a well known software in robotics simulation named V-REP . The API works well but I confront strange behavior. After I get joint feedback from the program using an external library supplied by software, UI is not updated until sub routine (having while loop) is finished. In other words, it only displays last value although I can log all values on output window. I even made large time delay, still no luck. I used the dispatcher technique to update the UI, still not working.

private void SetJointPosition(object sender, RoutedEventArgs e)
        {
            MoveJointsButton.IsEnabled = false;
            // Get the vrep handle of each position
            Vrep.simxGetObjectHandle(ClientId, "PhantomXPincher_joint1", out JointHandles[0], simx_opmode.oneshot_wait);
            Vrep.simxGetObjectHandle(ClientId, "PhantomXPincher_joint2", out JointHandles[1], simx_opmode.oneshot_wait);
            Vrep.simxGetObjectHandle(ClientId, "PhantomXPincher_joint3", out JointHandles[2], simx_opmode.oneshot_wait);
            Vrep.simxGetObjectHandle(ClientId, "PhantomXPincher_joint4", out JointHandles[3], simx_opmode.oneshot_wait);

            ////Assign Target positions
            TargetJointPosition[0] = (float)(JointBase.Value * (Math.PI / 180.0));
            TargetJointPosition[1] = (float)(JointShoulder.Value * (Math.PI / 180.0));
            TargetJointPosition[2] = (float)(JointElbow.Value * (Math.PI / 180.0));
            TargetJointPosition[3] = (float)(JointWrist.Value * (Math.PI / 180.0));

            //Set the position of each joint
            Vrep.SimSetJointTargetPosition(ClientId, JointHandles[0], TargetJointPosition[0]);
            Vrep.SimSetJointTargetPosition(ClientId, JointHandles[1], TargetJointPosition[1]);
            Vrep.SimSetJointTargetPosition(ClientId, JointHandles[2], TargetJointPosition[2]);
            Vrep.SimSetJointTargetPosition(ClientId, JointHandles[3], TargetJointPosition[3]);


            //Read Joint Position (start streaming)
            Vrep.SimGetJointPositionInit(ClientId, JointHandles[0]);
            Vrep.SimGetJointPositionInit(ClientId, JointHandles[1]);
            Vrep.SimGetJointPositionInit(ClientId, JointHandles[2]);
            Vrep.SimGetJointPositionInit(ClientId, JointHandles[3]);

            while ((Math.Abs(ActualJointPosition[0] - TargetJointPosition[0]) > 0.1) ||
                   (Math.Abs(ActualJointPosition[1] - TargetJointPosition[1]) > 0.1) ||
                   (Math.Abs(ActualJointPosition[2] - TargetJointPosition[2]) > 0.1) ||
                   (Math.Abs(ActualJointPosition[3] - TargetJointPosition[3]) > 0.1))
            {
                // Get current angle of each joint
                ActualJointPosition[0]=  Vrep.SimGetJointPositionRadian(ClientId, JointHandles[0]);
                ActualJointPosition[1] = Vrep.SimGetJointPositionRadian(ClientId, JointHandles[1]);
                ActualJointPosition[2] = Vrep.SimGetJointPositionRadian(ClientId, JointHandles[2]);
                ActualJointPosition[3] = Vrep.SimGetJointPositionRadian(ClientId, JointHandles[3]);


                //Update guages
                GBase.Dispatcher.Invoke(()=>
                {
                    GBase.Scales[0].Needles[0].Value = Math.Round(ActualJointPosition[0] * (180.0 / Math.PI));
                    Debug.WriteLine(DateTime.Now + " " + GBase.Scales[0].Needles[0].Value);
                }) ;

                GShoulder.Dispatcher.Invoke(() =>
                {
                    GShoulder.Scales[0].Needles[0].Value = ActualJointPosition[1] * (180.0 / Math.PI);
                });

                GElbow.Dispatcher.Invoke(() =>
                {
                    GElbow.Scales[0].Needles[0].Value = ActualJointPosition[2] * (180.0 / Math.PI);
                });

                GWrist.Dispatcher.Invoke(() =>
                {
                    GWrist.Scales[0].Needles[0].Value = ActualJointPosition[3] * (180.0 / Math.PI);
                });

            }

            Vrep.SimGetJointPositionEnd(ClientId, JointHandles[0]);
            Vrep.SimGetJointPositionEnd(ClientId, JointHandles[1]);
            Vrep.SimGetJointPositionEnd(ClientId, JointHandles[2]);
            Vrep.SimGetJointPositionEnd(ClientId, JointHandles[3]);

            MoveJointsButton.IsEnabled = true;

        }}
}

As you may see, I log joint position with no problem on the output window.

在此处输入图片说明

I use a WPF application.

This is because the while loop is being executed on the UI thread. You can't run a loop on and the update the UI on the same thread simultaneously.

That's why you should always perform any long-running work on a background thread and update UI at regular intervals using the dispatcher. Please refer to my answer here for more information about this:

How to create percentage of loop(processing) [c#]

You could try to execute while loop in a task, eg:

Task.Run(() =>
        {
            while (...)
            {
                //...

                //Update guages
                GBase.Dispatcher.Invoke(() =>
                {
                    GBase.Scales[0].Needles[0].Value = Math.Round(ActualJointPosition[0] * (180.0 / Math.PI));
                    Debug.WriteLine(DateTime.Now + " " + GBase.Scales[0].Needles[0].Value);
                });
                //..
            }
        }).ContinueWith(
        (t) =>
        {
            Vrep.SimGetJointPositionEnd(ClientId, JointHandles[0]);
            Vrep.SimGetJointPositionEnd(ClientId, JointHandles[1]);
            Vrep.SimGetJointPositionEnd(ClientId, JointHandles[2]);
            Vrep.SimGetJointPositionEnd(ClientId, JointHandles[3]);

            MoveJointsButton.IsEnabled = true;
        }, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());

Make sure that you marshal any code that access a UI control inside the task back to the UI thread using the dispatcher as controls can only be accessed on the thread on which they were originally created, ie the UI thread.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM