I have created a button in C# for Windows phone 7 development. It contains an animation and when clicked I want the animation to be shown, and then for the button to navigate to the next page.
Using Thread.Sleep(4000) just crashes the application and I was wondering how I go about this.
Is there a way to delay the navigate code?
private void batnballBtn_Click(object sender, RoutedEventArgs e)
{
NavigationService.Navigate(new Uri("/PictureGame.xaml", UriKind.Relative));
}
Presumably the animation is a Storyboard. You can navigate within the Storyboard's Completed event.
myStoryboard.Completed += (s, e) =>
{
myStoryboard.Stop();
NavigationService.Navigate(new Uri("/PictureGame.xaml", UriKind.Relative));
};
This way you don't need to predict how long the animation will take, making the code more reusable, and you don't have to worry about dealing with multiple threads manually.
Use a thread for that:
http://techkn0w.wordpress.com/2012/04/18/using-a-background-thread-in-windows-phone-7-wp7/
You're stopping the UI thread that's why the button is freeze.
There is only one thread responsible for managing the UI, so, if you block it when doing lengthy operations or making it sleep the UI process management is freezed until that work has finished.
Something like this:
private void batnballBtn_Click(object sender, RoutedEventArgs e)
{
ThreadPool.QueueUserWorkItem((WaitCallback)delegate(object state)
{
Thread.Sleep(4000);
this.Dispatcher.BeginInvoke((Action)delegate
{
NavigationService.Navigate(new Uri("/PictureGame.xaml", UriKind.Relative));
});
});
}
Related
I'm developing a C# WinForms application; this application will have many windows to show some reports. These windows are forms created from some DLLs by reflection, so the code is not so simple to change.
The problem is that when a form is getting data or processing some info it freeze/locks all the application, so users can't navigate to other forms in the application. So, if the user wants a report that takes 5 minutes, the app freeze 5 minutes and the user can't navigate to another window.
I have tried to call the new forms with Invoke((MethodInvoker)delegate () {}); but it freezes anyway. I tried to use MDI from Windows Forms, but also freezes. I tried to use Document Manager or Tab View from DevExpress, but the same problem.
I also have begun reading the problems to create a form in a new thread with the UI from the main thread, but I think this is not my problem because it's ok for the form to be freeze, but not to freeze all the application and user can navigate other forms.
If I try to create the forms in other process the application loads too slow because all the controls it has, so ideally it must be in the same process.
Is there any way I can call a new form in a new thread, that won't freeze all application while processing? Is there any opensource/paid control that can help me with this problem?
Thanks in advance, regards.
Simpliest way to do asynchronous programming in winforms and C# is async/wait logic.
Try something like this :
using System.Threading;
using System.Threading.Tasks;
private async void btnDoReport_Click(object sender, EventArgs e)
{
Task<bool> reportTask = new Task<bool>(ReportFunction); // if your function is void you can create it as Task reportTask = new Task(ReportFunction)
trainTask.Start(); // here your task - report is executed asynchronously and GUI does not freeze
bool reportResult = await reportTask; // wait on resposne from your reportTask
}
private bool ReportFunction()
{
// do what ever you need to in this function
return true;
}
You can also use BackgroundWorker class which is also working asynchronously and even you can raise event from your asynchronously running thread. After that this event you can catch in main thread - GUI thread, so you will be able to safely access controls of your GUI applications without errors.
using System.ComponentModel;
private BackgroundWorker bWork = new BackgroundWorker();
this.bWork.DoWork += BWork_DoWork;
this.bWork.ProgressChanged += bwork_ProgressChanged;
private void btnReport_Click(object sender, EventArgs e)
{
// this will run your code asynchronously
this.bWork.RunWorkerAsync();
}
private void BWork_DoWork(object sender, DoWorkEventArgs e)
{
// here you can create your report
// if you want you can raise event like this :
this.bWork.ReportProgress(this)
// and after raising of above event function : bWork_ProgressChanged is
//called where you can safely access main thread controls
}
private void bwork_ProgressChanged(object sender,
System.ComponentModel.ProgressChangedEventArgs e)
{
/* here you can access main thread GUI elements for example progress bar
without worrying of some problems because this function is called in
main thread space*/
}
I want to make a button to perform some action and THEN let user know it was done. I tried making a label ander a button, then pause, then making it disappear.
private void button1_Click(object sender, EventArgs e)
{
// some action
label1.Text = "Done!";
System.Threading.Thread.Sleep(500);
label1.Text = "";
}
But it doesn't work. What is my mistake?
As Grant says in his answer, you're blocking the UI thread. The simplest solution is to spawn a new Task which will do the update for you, thus releasing the UI thread.
The Task can simply use Invoke to push the update back to the UI thread after a Sleep.
In your case, this translates to something like this:
private void button1_Click(object sender, EventArgs e)
{
// some action
label1.Text = "Done!";
new TaskFactory().StartNew(() =>
{
Thread.Sleep(5000);
Invoke((Action)(() => label1.Text = string.Empty));
});
}
The call to Thread.Sleep() freezes the UI thread for a half-second, so that no updates to the UI can happen (including your update to the Label's text).
Here's a couple options:
You could use a BackgroundWorker, which has built-in mechanisms for executing long-running code in a separate thread, and then updating the UI (such as your Label) when it's done.
You could add a Windows.Forms.Timer to your Form, to perform the action and update the Label. Give it an interval of 500 (ms), and it'll wait roughly a half-second before firing.
I have a question related to a simple task: update the control status from any class in the namespace.
In detail I have written a GUI that opens different forms from listbox (each row opens a different form). In some cases the form called has to retrieve data from SQL database, in this kind of scenario I'd like to insert a couple of custom controls (LED) in order to signal to the user when the system is retrieving data (RED LED) or is ready (GREEN LED).
Basically the result is that I'm not able to update these controls during the form loading, I have noticed that a good way can be the backgroundworker but not sure if it is right.
Do you have any idea how to manage it?
Yes, you would need to use a BackgroundWorker or some other asynchronous operation. If you do your logic during FormLoad, which is a synchronous operation, you won't see any updates in your form no matter what.
So, for example with a background worker:
BackgroundWorker bw;
private void Form1_Load(object sender, EventArgs e)
{
bw = new BackgroundWorker();
bw.WorkerReportsProgress = true; //allows call backs
bw.DoWork += bw_DoWork;
bw.ProgressChanged += bw_ProgressChanged;
bw.RunWorkerAsync(); //run the worker
}
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
var message = e.UserState;
//do something with the UserState on the UI, like flash a light
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker localBW = (BackgroundWorker)sender;
//do your logic here, when you want to "report progress"
//use the following lines
localBW.ReportProgress(0, "hey, flash please"); // or something else
//when you are all done, you can pass something back
e.Result = "I'm done now";
}
For more reading, see the msdn page on BackgroundWorker, a "How to:" using a BackgroundWorker, and Asynchronous Programming with Async and Await (a newer topic with .net 4.0 and up).
At the end of a drag&drop operation, I'm showing a form using ShowDialog.
Problem: When the form is closed, my main form is pushed behind any other application windows.
Code:
private void ctrl_DragDrop(object sender, DragEventArgs e) {
// ...
if (e.Effect == DragDropEffects.Move) {
string name = e.Data.GetData(DataFormats.Text).ToString();
viewHelperForm.ShowDialog(view.TopLevelControl);
// ...
}
Question: What can I do that the main form stays on top?
Your ShowDialog() call is blocking the DragDrop event. That is very, very bad, it gums up the drag source and make it go catatonic and unresponsive to Windows messages. This has all kinds of side-effects, like your window going catatonic as well or not getting reactivated since the D+D operation isn't completed yet.
Avoid this by only displaying the dialog after the D+D operation is completed. Elegantly done by taking advantage of the Winforms plumbing that allows posting a message to the message queue and get it processed later. Like this:
private void ctl_DragDrop(object sender, DragEventArgs e) {
//...
this.BeginInvoke(new Action(() => {
viewHelperForm.ShowDialog(view.TopLevelControl);
}));
}
I've done some reseach on the life cycle of Windows Phone apps and I've gathered that when the phone is locked whilst an app is still running, and you unlock the phone the 'Application_Activated' function is called in the App.xaml.cs file.
// Code to execute when the application is activated (brought to foreground)
// This code will not execute when the application is first launched
private void Application_Activated(object sender, ActivatedEventArgs e)
{
//Code to run
MessageBox.Show("Hello there!");
}
Now in the above example, the simple 'MessageBox' call doesn't get run. Like I said, if you have your app running and you lock the phone, and then unlock the phone the above code is expected to run, in this case display a MessageBox as soon as you unlock the phone.
Any help would really be appreciated! Thanks.
You can not do that
If you call Show(String) method from the app Activated and Launching event
handlers an InvalidOperationException is thrown with the message Error
Displaying MessageBox.
it is in msdn
if you wanna show same message my suggestion is to use OnNavigatedTo event
EDIT
if i understood correctly you wanna change default page navigation
1.One way to do this:
In WMAppManifest.xml replace the property of Navigation Page with your desire page
An alternative:
In WMAppManifest.xml remove the property of Navigation Page
private void Application_Launching(object sender, LaunchingEventArgs e)
{
RootFrame.Navigate(new Uri("YourPage.xaml", UriKind.Relative));
}
private void Application_Activated(object sender, ActivatedEventArgs e)
{
RootFrame.Navigate(new Uri("YourPage.xaml", UriKind.Relative));
}
This way you can "play" with IsolatedStorageSettings for example
if (boolvariable)
{
RootFrame.Navigate(new Uri("YourPage.xaml", UriKind.Relative));
boolvariable = false;
}
else
{
RootFrame.Navigate(new Uri("/MainPage.xaml", UriKind.Relative));
}
It just an idea, let me know how it goes (: