Change the value of ProgressBar after executing each task in WPF? - wpf

I want to change the value of the ProgressBar automatically after I executing a method in my WPF project. Here is how my code looks like,
ChangeValueOfProgressBar()
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
this.progressBar.Value = 0;
}));
DoTaskA();
this.Dispatcher.BeginInvoke(new Action(() =>
{
this.progressBar.Value = 50;
}));
DoTaskB();
this.Dispatcher.BeginInvoke(new Action(() =>
{
this.progressBar.Value = 100;
}));
}
and I expect that the value will change to 50 after I finish DoTaskA() method, then turn out to be 100 when DoTaskB() have been done, too. However, the value doesn't change untill DoTaskB been done.
How do I achieve my goal?? Thanks in advance!

I found the answer! Just reference the site :
http://www.wpf-tutorial.com/misc-controls/the-progressbar-control/
and it works perfectly!

Related

DataGrid Update Instantly [duplicate]

I tried to use the below code to make a 2 second delay before navigating to the next window. But the thread is invoking first and the textblock gets displayed for a microsecond and landed into the next page. I heard a dispatcher would do that.
Here is my snippet:
tbkLabel.Text = "two mins delay";
Thread.Sleep(2000);
Page2 _page2 = new Page2();
_page2.Show();
The call to Thread.Sleep is blocking the UI thread. You need to wait asynchronously.
Method 1: use a DispatcherTimer
tbkLabel.Text = "two seconds delay";
var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(2) };
timer.Start();
timer.Tick += (sender, args) =>
{
timer.Stop();
var page = new Page2();
page.Show();
};
Method 2: use Task.Delay
tbkLabel.Text = "two seconds delay";
Task.Delay(2000).ContinueWith(_ =>
{
var page = new Page2();
page.Show();
}
);
Method 3: The .NET 4.5 way, use async/await
// we need to add the async keyword to the method signature
public async void TheEnclosingMethod()
{
tbkLabel.Text = "two seconds delay";
await Task.Delay(2000);
var page = new Page2();
page.Show();
}
Method 4: .NET 5.0+
Task.WaitAll(new Task[] { Task.Delay(2000) });
This solution has no downsides. It can be used in loops which is for "DispatcherTimer" and "ContinueWith" impossible.

Cypress while loop [duplicate]

I have 15 buttons on a page. I need to test each button.
I tried a simple for loop, like
for (var i = 1; i < 15; i++) {
cy.get("[=buttonid=" + i + "]").click()
}
But Cypress didn't like this. How would I write for loops in Cypress?
To force an arbitrary loop, I create an array with the indices I want, and then call cy.wrap
var genArr = Array.from({length:15},(v,k)=>k+1)
cy.wrap(genArr).each((index) => {
cy.get("#button-" + index).click()
})
Lodash is bundled with Cypress and methods are used with Cypress._ prefix.
For this instance, you'll be using the _.times. So your code will look something like this:
Cypress._.times(15, (k) => {
cy.get("[=buttonid=" + k + "]").click()
})
You can achieve something similar to a "for loop" by using recursion.
I just posted a solution here: How to use a while loop in cypress? The control of is NOT entering the loop when running this spec file? The way I am polling the task is correct?
Add this to your custom commands:
Cypress.Commands.add('recursionLoop', {times: 'optional'}, function (fn, times) {
if (typeof times === 'undefined') {
times = 0;
}
cy.then(() => {
const result = fn(++times);
if (result !== false) {
cy.recursionLoop(fn, times);
}
});
});
Then you can use it by creating a function that returns false when you want to stop iterating.
cy.recursionLoop(times => {
cy.wait(1000);
console.log(`Iteration: ${times}`);
console.log('Here goes your code.');
return times < 5;
});
While cy.wrap().each() will work (one of the answers given for this question), I wanted to give an alternate way that worked for me. cy.wrap().each() will work, but regular while/for loops will not work with cypress because of the async nature of cypress. Cypress doesn't wait for everything to complete in the loop before starting the loop again. You can however do recursive functions instead and that waits for everything to complete before it hits the method/function again.
Here is a simple example to explain this. You could check to see if a button is visible, if it is visible you click it, then check again to see if it is still visible, and if it is visible you click it again, but if it isn't visible it won't click it. This will repeat, the button will continue to be clicked until the button is no longer visible. Basically the method/function is called over and over until the conditional is no longer met, which accomplishes the same thing as a for/while loop, but actually works with cypress.
clickVisibleButton = () => {
cy.get( 'body' ).then( $mainContainer => {
const isVisible = $mainContainer.find( '#idOfElement' ).is( ':visible' );
if ( isVisible ) {
cy.get( '#idOfElement' ).click();
this.clickVisibleButton();
}
} );
}
Then obviously call the this.clickVisibleButton() in your test. I'm using typescript and this method is setup in a class, but you could do this as a regular function as well.
// waits 2 seconds for each attempt
refreshQuote(attempts) {
let arry = []
for (let i = 0; i < attempts; i++) { arry.push(i) }
cy.wrap(arry).each(() => {
cy.get('.quote-wrapper').then(function($quoteBlock) {
if($quoteBlock.text().includes('Here is your quote')) {
}
else {
cy.get('#refreshQuoteButton').click()
cy.wait(2000)
}
})
})
}
Try template literals using backticks:
for(let i = 0; i < 3; i++){
cy.get(`ul li:nth-child(`${i}`)).click();
}

WPF - Set Window Owner

I have the following case:
A window is shown the the reference to that is stored in a utility class.
Later a modal dialog needs to appear above that window; so I am doing the following:
OptionalMessageBox message = new OptionalMessageBox(title, errorMessage.ToString(), MessageImage.Warning);
if (UIUtilities.TopWindow != null)
{
UIUtilities.TopWindow.Dispatcher.Invoke(() => message.Owner = UIUtilities.TopWindow);
UIUtilities.TopWindow.Dispatcher.Invoke(() => message.ShowDialog());
}
else
{
message.ShowDialog();
}
However this is give the classic 'The calling thread cannot access this object because a different thread owns it' though I don't understand why as I am using the dispatcher for the TopWindow variable. As a note (and out of desperation) I tried putting the calls on the message variable I just created - that didn't work either but I didn't expect that to be the problem as how can I now own it if I have just made it!
Any advice would be greatly appreciated.
Try this:
if (UIUtilities.TopWindow != null)
{
UIUtilities.TopWindow.Dispatcher.Invoke(() =>
{
var message = new OptionalMessageBox(title, errorMessage.ToString(), MessageImage.Warning);
message.Owner = UIUtilities.TopWindow;
message.ShowDialog();
});
}
else
{
var message = new OptionalMessageBox(title, errorMessage.ToString(), MessageImage.Warning);
message.ShowDialog();
}
You can use this
App.Current.Dispatcher.Invoke(() => {
OptionalMessageBox message = new OptionalMessageBox(title, errorMessage.ToString(), MessageImage.Warning);
message.Owner = App.Current.MainWindow;
message.ShowDialog();
});

Busy indicator does not show until data shows

I have a control in my project that provides a busy indicator (rotating circle). I'd like it to run when a user selects a file to load data into a data grid. The busy indicator does not show up until my data grid is populated though. How can I get my busy indicator to show while the data is being retrieved? I believe I'm supposed to use a thread, but am not too knowledgeable with them yet and am trying to learn. I've tried many different ways and below is my latest attempt, which I do not know if I am anywhere close.
public void DoWork()
{
this.StartProgressBar();
Task.Factory.StartNew(() =>
{
UIDispatcher.Current.BeginInvoke(() =>
{
if (fileCompleted != null && !string.IsNullOrEmpty(fileCompleted.SelectedFile))
{
this.TestResults.Clear();
LoadedFileInfo info = this.Model.OpenTestCompleted(fileCompleted.SelectedFile);
foreach (var model in info.Sequence.Models)
{
foreach (var details in model.Tests)
{
this.TestResults.Add(new TestResultsModel(details, model.Name.Substring(0, model.Name.IndexOf('.'))));
}
}
}
});
});
}
private void StartProgressBar()
{
TaskScheduler scheduler = TaskScheduler.FromCurrentSynchronizationContext();
CancellationToken cancelationToken = new CancellationToken();
Task.Factory.StartNew(() => this.StopProgressBar()).ContinueWith(
m =>
{
this.ToggleProgressBar = true;
},
cancelationToken,
TaskContinuationOptions.None,
scheduler);
}
private void StopProgressBar()
{
this.ToggleProgressBar = false;
}
I really agree with #Ben, you should research how to use Tasks. You are creating background threads, and doing work on the UI thread in them anyway, which inevitably hold the UI thread. Try something simpler and see if it works. As far as your cancellation token goes, I don't see how and were you'd be able to reset it, as it is not a property in your class, so here's a sample without it..
How about something like this:
public void DoWork()
{
//done on the UI thread
this.ToggleProgressBar = true;
//done on the background thread, releasing UI, hence should show the progress bar
Task.Factory.StartNew(() =>
{
if (fileCompleted != null && !string.IsNullOrEmpty(fileCompleted.SelectedFile))
{
this.TestResults.Clear();
LoadedFileInfo info = this.Model.OpenTestCompleted(fileCompleted.SelectedFile);
foreach (var model in info.Sequence.Models)
foreach (var details in model.Tests)
this.TestResults.Add(new TestResultsModel(details, model.Name.Substring(0, model.Name.IndexOf('.'))));
}
//after all that (assumingly heavy work is done on the background thread,
//use UI thread to notify UI
UIDispatcher.Current.BeginInvoke(() =>
{
this.ToggleProgresBar = false;
}
});
}

Invoke mouse curser when using task

Im using task process and and during the process I want to invoke the mouse
courser ,how should I do that ?
Task.Factory.StartNew(() =>
{
try
{
_isEnabled = false;
_canBack = false;
....
I've tried with the following which is not work...
System.Windows.Input.Cursors.Wait;
Set the window cursor on entry and exit of task. Since you can access window object only on UI thread so for accessing cursor property you have to delegate it on UI thread.
Task.Factory.StartNew(() =>
{
Application.Current.Dispatcher.Invoke(new Action(() =>
Cursor = Cursors.Wait));
Thread.Sleep(5000); // Some time consuming operation here.
Application.Current.Dispatcher.Invoke(new Action(() =>
Cursor = Cursors.Arrow));
});
You can try like following:
Application.Current.Dispatcher.Invoke((Action) (() => { Mouse.OverrideCursor = Cursors.Wait; }));
Good luck

Resources