In this particular situation, there are 9 automated steps in a process that take varying lengths of time. We currently have a number showing percentage in the center of a progress bar, but it suffers from the common stop-and-go problem of racing up to 33%, waiting a long time, racing up to 55%, waiting an even longer time, then finishing.
What's the best way to present this to the user? Should we remove the number, remove the whole progress bar in favor of an ajax-type circle animation, add descriptive text for the nine steps and checking them off or leave it the way it is? What are your thoughts?
If it really takes a long time, AJAX type of animation is probably not a good idea. I'd go with checklist of items.
The progress bar serves to reassure the user that something is going on. When you do not have a more detailed list of steps, I would recommend 'faking' them.
A basic solution would be to run a timer and slowly increase the progress, capping it at the next logic step value. If the steps take wildly different amounts of time, you can manually adjust the delta value for every timer 'tick' depending in which step you're in.
However, a better solution (I once implemented it this way, but I cannot post the code :)), would be to slowly decrease the delta as the step continues -- so it never quite makes it to the next step. Then the next step arrives, you have a nice jump and the cycle repeats.
In some cases it's more important for a progress bar to indicate that something is happening than for it to be accurate and smooth. Users tend to panic when progress bars stop progressing.
If you have problems with the bar freezing for periods of time, it might be better to replace it with a generic animation that reassures the user that something is happening without worrying about showing how far along the process is. Or, leave the progress bar in place, but add some additional animation as a placebo.
To expand Cadet Pirx's answer, here's some WinForms C# code. You'll need a new UserControl. Put a ProgressBar control on it, called inner. Add the following code:
public partial class ZenoProgressBar : UserControl
{
private const int DEFAULT_FACTOR_VALUE = 10;
private const int DEFAULT_MAXIMUM_VALUE = 100;
public ZenoProgressBar()
{
InitializeComponent();
Maximum = DEFAULT_MAXIMUM_VALUE;
Factor = DEFAULT_FACTOR_VALUE;
}
/// <summary>
/// The "speed" of the progress bar. While it will never get to
/// the end, it uses this number to decide how much further to
/// go each time Increment is called. For example, setting it to
/// 2 causes half of the remaining distance to be covered.
/// </summary>
[DefaultValue(DEFAULT_FACTOR_VALUE)]
public int Factor { get; set; }
[DefaultValue(DEFAULT_MAXIMUM_VALUE)]
public int Maximum { get; set; }
private void ZenoProgressBar_Load(object sender, EventArgs e)
{
inner.Dock = DockStyle.Fill;
}
public void Increment()
{
inner.Value += (inner.Maximum - inner.Value) / Factor;
}
}
I had almost the exact same problem. We also had 9 steps, so the bar would go 11%, 22% 33% etc. and also with some steps taking longer than others.
I decided to make two of the longer steps count as two, so we how had 11 steps, so it wasn't as obvious, and the jumps weren't always even: 9%, 18%, 36%, 45%, 54%, 72%, 81%, 90%, done. The step values were always the same, but since the size of the step wasn't obvious, it worked..
Related
I have a watch that updates at non standard time intervals (eg half minutes).
It made sense, to me, to use app_timer_register to update the time which seems to make tick_time_service_subscribe redundant.
Should I expect any issues with the substitution.
So far, the following code seems to be working on CloudPebble.
static void timeHandler(void * data){
find_time_to_next_update(); // updates int time_to_next_update_ms
app_timer_register(time_to_next_update_ms, timeHandler, NULL);
update_time(); // refreshes watch face
}
I've added Coded UI Tests to my ASP.NET MVC solution in Visual Studio 2013. I was dismayed to see how slowly the tests run; each page just sits there for up to a minute or more before the test machinery wakes up and starts filling in the form fields.
After some experimentation (including turning off SmartMatch), I've discovered that simply calling
Playback.PlaybackSettings.WaitForReadyLevel = WaitForReadyLevel.Disabled;
solves the problem. But, as expected, the test frequently fails because the UI thread isn't ready for the test machinery to interact with the controls on the form.
Calling
Playback.PlaybackSettings.WaitForReadyLevel = WaitForReadyLevel.UIThreadOnly;
makes the test run reliably, if slowly.
Any thoughts or suggestions? Any hope that someone might have some insight into the magic baked into the WaitForReady machinery? Are there any other settings related to WaitForReady that I can fiddle with besides WaitForReadyLevel?
After a bit of experimentation, I've worked out what appears to be a combination of settings that allows my Coded UI Tests to reliably run at full speed -- faster than I could interact with the website by hand.
Note: The relevant "documentation" (if you call a blog "documentation") can be found here:
Playback configuration settings
Retrying failed playback actions.
The trick requires several modifications to the default playback settings:
Setting WaitForReadyLevel = WaitForReadyLevel.Disabled allows the test to run at full speed. But it also disables the (slow!) magic that waits until it's safe to interact with controls on the page.
Setting a MaximumRetryCount and attaching an error handler deals with most of the errors that result from disabling the "wait for ready" magic. Because I've baked a 1 second Sleep into the retry logic, this value is effectively the number of seconds I'm willing to wait for the page to load and become responsive.
Apparently, failure to find the control under test is not one of the errors handled by the error handler/retry mechanism. If the new page takes more than a few seconds to load, and the test is looking for a control that doesn't exist until the new page loads, the test fails to find the control and the test fails. Setting ShouldSearchFailFast = false solves that problem by giving you the full timeout time for your page to load.
Setting DelayBetweenActions = 500 appears to work around a problem that I see occasionally where the UI misses a button click that occurs immediately after a page has loaded. The test machinery seems to think that the button was clicked, but the web page doesn't respond to it.
The "documentation" says that the default search timeout is 3 minutes, but it's actually something greater than 10 minutes, so I explicitly set SearchTimeout to 1 second (1000 ms).
To keep all of the code in one place, I've created a class that contains code used by all of the tests. MyCodedUITests.StartTest() is called by the [TestInitialize] method in each of my test classes.
This code really should be executed only once for all of the tests (rather than once per test), but I couldn't figure out a way to get the Playback.PlaybackSettings calls to work in the [AssemblyInitialization] or [ClassInitialization] routines.
/// <summary> A class containing Coded UI Tests. </summary>
[CodedUITest]
public class UI_Tests
{
/// <summary> Common initialization for all of the tests in this class. </summary>
[TestInitialize]
public void TestInit()
{
// Call a common routine to set up the test
MyCodedUITests.StartTest();
}
/// <summary> Some test. </summary>
[TestMethod]
public void SomeTest()
{
this.UIMap.Assert_HomePageElements();
this.UIMap.Recorded_DoSomething();
this.UIMap.Assert_FinalPageElements();
}
}
/// <summary> Coded UI Test support routines. </summary>
class MyCodedUITests
{
/// <summary> Test startup. </summary>
public static void StartTest()
{
// Configure the playback engine
Playback.PlaybackSettings.WaitForReadyLevel = WaitForReadyLevel.Disabled;
Playback.PlaybackSettings.MaximumRetryCount = 10;
Playback.PlaybackSettings.ShouldSearchFailFast = false;
Playback.PlaybackSettings.DelayBetweenActions = 500;
Playback.PlaybackSettings.SearchTimeout = 1000;
// Add the error handler
Playback.PlaybackError -= Playback_PlaybackError; // Remove the handler if it's already added
Playback.PlaybackError += Playback_PlaybackError; // Ta dah...
}
/// <summary> PlaybackError event handler. </summary>
private static void Playback_PlaybackError(object sender, PlaybackErrorEventArgs e)
{
// Wait a second
System.Threading.Thread.Sleep(1000);
// Retry the failed test operation
e.Result = PlaybackErrorOptions.Retry;
}
}
Coded UI searches for controls on the screen and that search is quite fast if successful. However if the search fails then Coded UI has another try using a "smart match" method and that can be slow. The basic way of avoiding Coded UI falling back to using smart matching is to remove or simplify search items that may change from run to run.
This Microsoft blog gives lots of explanation of what happens and how to fix it. The example therein shows a speedup from 30 seconds to 8 seconds by changing a search string from
Name EqualsTo “Sales order (1 - ceu) - Sales order: SO-101375, Forest Wholesales”
to
Name Contains “Sales order (1 - ceu) - Sales order: SO”
Seems like it is captured from microsoft dynamics tool. Please check the length of the string captured from inspect tool. You will be finding some hidden character. just order (1 - ceu). Else just move the cursor from "(" to ")". You will be finding cursor is not moving sometime when pressing right arrow key.
I'm creating a game with XNA 4.0 and I have a problem with resetting the game time in my game,
the problem is I'm using this code for adding my objects in game:
Timespan prevSpawn = timespan.zero;
Timespan objectSpawnTime = timespan.fromsec(5);
if (gameTime.TotalGameTime - prevSpawn> objectSpawnTime)
{
prevSpawn = gameTime.TotalGameTime;
AddObject();
}
I want to reset the game time to zero, when start the game again or game end and goes to mainmenu and hit the play again, I want to reset gametime.
As i understand from the MSDN entry below, the GameTime.TotalGameTime property will continue 'ticking' until you end the game, or, entire application.
http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.gametime.totalgametime.aspx
Perhaps it would be wiser to use your own object, for which you can reset with any of your actions and hence have more control over the time span. Then you could still use this property for counting the difference from one and the other.
i.e. when you reset/restart etc, do not refer to TotalGameTime and try to make it be zero, but refer to your own object's timespan, or to (TotalGameTime - TimeWhenReset) where TimeWhenReset is the timespan copied from TotalGameTime when you reset.
This is untested, but I think that it should work if I understood correctly.
For a more accurate timer, you would be better using a time span, and a DateTime vairable. Set the DateTime to now when you want to start the timer, and in the TimeSpan do something like this:
timer = StartTime - DateTime.Now;
This will give you a timer you can deploy at any time.
Using the physics helper library.
I'm trying to figure out how I can determine whether a physics object is at rest. Does anyone know how to do this or have any ideas of what I could do?
An example scenario is a bouncy ball that can be picked up and thrown around. I tried creating a timer that times each individual bounce from a collision event with the floor and determines if the object is at rest based off of that but this does not work for if the user slides the ball to the left and right.
Any suggestions?
If you have runtime access to the underlying Farseer Body, then you also should have access to the property LinearVelocity, which you can check for 0 magnitude.
This is pretty basic stuff. Your physics object should be an instance of some kind of class which contains information on the object's position, velocity, etc etc. At any given time, you should be able to check the speed of the object, and obviously if its speed == 0, it is at rest.
So far I've came up with a simple method. Creating two class variables (Vector2 currentPosition, Vector2 previousPosition) and then creating a dispatcher timer that ticks every so often and using the following tick method:
void bounceTimer_Tick(object sender, EventArgs e)
{
currentPosition = ball.Position;
if (currentPosition == previousPosition)
{
// Object at rest
}
else
{
// Object moving
}
}
previousPosition = currentPosition;
}
There are some issues with it though for example if it captures the balls position in the air coming up and then back down at the same position (very unlikely) and at a very high frequency in ticking it can sometimes capture the same position unexpectedly, at a slow frequency of ticking it takes time to determine if the object is at rest, anyone else have a better method?
Our team is creating a new recruitment workflow system to replace an old one. I have been tasked with migrating the old data into the new schema. I have decided to do this by creating a small Windows Forms project as the schema are radically different and straight TSQL scripts are not an adequate solution.
The main sealed class 'ImportController' that does the work declares the following delegate event:
public delegate void ImportProgressEventHandler(object sender, ImportProgressEventArgs e);
public static event ImportProgressEventHandler importProgressEvent;
The main window starts a static method in that class using a new thread:
Thread dataProcessingThread = new Thread(new ParameterizedThreadStart(ImportController.ImportData));
dataProcessingThread.Name = "Data Importer: Data Processing Thread";
dataProcessingThread.Start(settings);
the ImportProgressEvent args carries a string message, a max int value for the progress bar and an current progress int value. The Windows form subcribes to the event:
ImportController.importProgressEvent += new ImportController.ImportProgressEventHandler(ImportController_importProgressEvent);
And responds to the event in this manner using it's own delegate:
private delegate void TaskCompletedUIDelegate(string completedTask, int currentProgress, int progressMax);
private void ImportController_importProgressEvent(object sender, ImportProgressEventArgs e)
{
this.Invoke(new TaskCompletedUIDelegate(this.DisplayCompletedTask), e.CompletedTask, e.CurrentProgress, e.ProgressMax);
}
Finally the progress bar and listbox are updated:
private void DisplayCompletedTask(string completedTask, int currentProgress, int progressMax)
{
string[] items = completedTask.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
foreach (string item in items)
{
this.lstTasks.Items.Add(item);
}
if (currentProgress >= 0 && progressMax > 0 && currentProgress <= progressMax)
{
this.ImportProgressBar.Maximum = progressMax;
this.ImportProgressBar.Value = currentProgress;
}
}
The thing is the ListBox seems to update very quickly, but the progress bar never moves until the batch is almost complete anyway ??? what gives ?
Maybe you can try the BackgroundWorker component. It makes threading easier. Examples here:
BackgroundWorker Threads and Supporting Cancel
Using the BackgroundWorker Component in .NET 2 applications
BackgroundWorker Sample
Maybe outside of the scope but, to sometimes its useful to do an Application.DoEvents(); to make the gui parts react to user input, such as pressing the cancel-button on a status bar dialog.
Do you by any chance run Windows Vista? I've noticed the exactly same thing in some work related applications. Somehow, there seem to be a delay when the progress bar "animates".
#John
Thanks for the links.
#Will
There's no gain from threadpooling as I know it will only ever spawn one thread. The use of a thread is purely to have a responsive UI while SQL Server is being pounded with reads and writes. It's certainly not a short lived thread.
Regarding sledge-hammers you're right. But, as it turns out my problem was between screen and chair after all. I seem to have an unusal batch of data that has many many many more foreign key records than the other batches and just happens to get selected early in the process meaning the currentProgress doesn't get ++'d for a good 10 seconds.
#All
Thanks for all your input, it got me thinking, which got me looking elsewhere in the code, which led to my ahaa moment of humility where I prove yet again the error is usually human :)
Are you sure that the UI thread is running freely during all this process? i.e. it's not sitting blocked-up on a Join or some other wait? That's what it looks like to me.
The suggestion of using BackgroundWorker is a good one - definitely superior to trying to sledge-hammer your way out of the problem with a load of Refresh/Update calls.
And BackgroundWorker will use a pool thread, which is a friendlier way to behave than creating your own short-lived thread.
There's no gain from threadpooling as
I know it will only ever spawn one
thread. The use of a thread is purely
to have a responsive UI while SQL
Server is being pounded with reads and
writes. It's certainly not a short
lived thread.
OK, I appreciate that, and glad you found your bug, but have you looked at BackgroundWorker? It does pretty much exactly what you're doing, but in a standardised fashion (i.e. without your own delegates) and without the need to create a new thread - both of which are (perhaps small, but maybe still useful) advantages.