I'm currently working on a snip tool that captures an image of the screen. When I click "New Snip" the program needs to create a screen capture after the tool window has minimized. It currently works like this.
//Minimize Tool Window
WindowState = WindowState.Minimized;
//Set delay to allow window to finish its minimizing animation
Thread.Sleep(200);
//Show screen capture with snipping
SnippingWindow sw = new SnippingWindow();
sw.ShowDialog();
//Close minimized window
Close();
Is there a way to wait for the WindowState change animation to finish before calling the SnippingWindow? I would prefer not to make a Thread.Sleep call, but it's the only thing that seems to be working.
I could close the window prior to calling the Snip, but that doesn't seem to "get it out of the way" in time either as it's executed on the same thread.
I eventually figured out a workaround (although not very clean, but it avoids having to using Sleep).
I bound the Window's Opacity to a value that can be changed with a BackgroundWorker. When the BackgroundWorker starts it sets the opacity to 0. Once the worker is complete the RunWorkerCompleted event handles the new snip screen shot.
This ensures the tool window is out of the way before the screen shot is taken.
I tried to simply Close the window from the background worker first, but it didn't execute the close operation correctly.
private void Bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Close();
SnippingWindow sw = new SnippingWindow();
sw.ShowDialog();
}
private void Bw_DoWork(object sender, DoWorkEventArgs e)
{
//Windows Opacity is bound to this value.
//I had to implement iNotifyPropertyChanged on this property.
OpacityValue = 0;
}
Related
I began using C# and WPF a few months ago and now I thought I'd try to learn some new techniques like using threading. So I have an app that I want to run all the time (using an infinity while loop) but show the dialog (main window) every minute. So I am doing this by using Threading and here is how i am doing this:
public MainWindow()
{
InitializeComponent();
while (true)
{
callmyfunction()
system.Threading.Thread.Sleep(1000);
}
}
In my callmyfunction(), I am calling the dialog (which is the main WPF application) so it will show. Here's how i am doing it:
public void callmyfunction()
{
this.ShowDialog();
}
I have a regular button and when you click on it, it should hide the main window. So my button function is like this:
private void Button_Click2(object sender, RoutedEventArgs e)
{
this.Hide();
}
So what I am doing is, I am loading the main window normally and it has a button, when I click on that button, it should hide the main window and the window should sleep as per the milli-seconds I specified in thread.sleep and then it will wake up, then again the dialog will appearand it will show the button and so on and so forth. This loop is working fine with me, but the issue I am having is that after the first dialog appears and I click on the button to hide the main window, the second time the main window appears, the button would appear as a "pressed" button, not as a new button. I think it's because I "pressed" on it the first time the main window appeared. And it stays like that until I stop the program and run it again.
So my question is, any idea how I can "reset" the button control? Or do I need to reset the mouse click event? Any pointers on this would be helpful.
You should run the loop on a background thread. If you run it on the UI thread, the application won't be able to respond to user input.
The easiest and recommended way to run some code on a background thread is to start a new Task.
Also note that you cannot access the window from a background thread so you need to use the dispatcher to marshal the call back to the UI thread.
The following sample code should give you the idea.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Task.Factory.StartNew(() =>
{
while (true)
{
Dispatcher.Invoke(() => callmyfunction());
System.Threading.Thread.Sleep(5000);
}
}, TaskCreationOptions.LongRunning);
}
public void callmyfunction()
{
WindowState = WindowState.Normal;
}
private void Button_Click2(object sender, RoutedEventArgs e)
{
WindowState = WindowState.Minimized;
}
}
I have a main UI that doing some time-consuming work. When it is executing, I would like to open a second form with a progress bar (marquee style) to indicate "working on it".
I have seen people putting the time-consuming task in the BackgroundWorker, however, I would like to run in the main UI thread.
The time-consuming task will be executed in MainForm. I would like to reuse the progress bar for various process, so I am writing a second form ProgressBarForm with BackgroundWorker in it, that would start the _mainWork at the same time as showing progress bar, and will stop and close the ProgressBarForm when _mainWork is done.
Because forms are modals, I am thinking of showing ProgressBarForm in the BackgroundWorker in order not to block MainForm.
Please note that I am not running mainForm in BackgroundWorker. My backgroundWorker just show the form and perhaps report a timer.
public partial class ProgressBarFom : UControl
{
public delegate void MainWork();
private MainWork _mainWork;
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//progressBar.Hide();
this.OnClose(sender, e);
//
backgroundWorker.Dispose();
}
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
//show this ProgressBarForm
this.ShowDialog();
//stop backgroundWorker
//calling this.Close() in RunWorkerComplete
if (backgroundWorker.CancellationPending == true)
{
e.Cancel = true;
return;
}
}
public void CallProgressBar(object sender, EventArgs e)
{
//progressBar.Show();
backgroundWorker.RunWorkerAsync();
_mainWork();
if (backgroundWorker.IsBusy)
backgroundWorker.CancelAsync();
}
}
In MainForm, I am passing mainwork and call ExecWithProgressBar
private void ExecWithProgressBar()
{
ProgressBarFom .MainWork mainWork = new ProgressBarFom .MainWork(ProgressBarMainWork);
ProgressBarFom prBar = new ProgressBarFom (mainWork);
prBar.CallProgressBar(null, null);
}
Some problems I encoutered
Inside DoWork, the same modal issue occurs. ShowDialog() will block the thread and therefore I never get to check CancellationPending to close ProgressBarForm.
ProgressBarForm starts later then the mainWork. I thought when I called CallProgressBar, the backgroundWorker should start well before my mainWork.
Is worker.Dispose() necessary in RunWorkerComplete?
Would it be a better choice to run mainWork in Worker? And why? I decided to let the main thread run this to not disturb the normal flow, what in Main thread will remain in Main thread, Progress bar is like an addon. If we bring it to the worker, would we need another thread to for progress bar itself?
Unless you do some very ugly hacks (like running more than one message loop inside your application) you cannot display a dialog if the thread running the main window is busy. All dialogs use the same thread to do the display update stuff in WinForms. In fact, they even must be running on the same thread.
There's one (sometimes acceptable) hack using Application.DoEvents(), but I wouldn't use it either, because it gets you into a lot of problems as well.
So the simple answer is: This doesn't work. Use a background worker to do lengthy processing.
we have a programm where you can calculate several points (x/y).
afterwards you can draw the graph by clicking at a "draw" button. (chart object)
The graph is shown in a new window so there is a close button that allows
you to close it again and also killing the task. But there is also this standard cross button in the right corner of the new window's frame. If you click the standard cancel button instead of our own, the window is also closed but the task for the new window is still running in background.
Is there a proper way to also kill the task with the standard button?
Thanks ahead!
You could use the FormClosing Event.
In that event you can then kill the task.
Example:
private void Form1_FormClosing(Object sender, FormClosingEventArgs e) {
// Do your closing here:
}
Here is a link: http://msdn.microsoft.com/en-us/library/system.windows.forms.form.formclosing(v=vs.110).aspx
I am new to multi-threading. I am doing a project using wpf.
Brief introduction to my project:
One mainwindow
One method in mainwindow creates another thread that creates another window, which is called window 2.
Whenever window 2 is visible, mainwindow is suspended(so i used join() method to suspend the main thread)
The problem is whenever I closed the window 2, the new thread doesn't terminate. so the main thread is forever suspended. So how to solve this problem.
The following code is where i create a new thread for window 2 in MainWindow Class:
private void Button_Click_1(object sender, RoutedEventArgs e)
{
Thread addThread = new Thread(CreateCourseWindow);
addThread.SetApartmentState(ApartmentState.STA);
addThread.Start();
Thread.Sleep(TimeSpan.FromSeconds(1));
addThread.Join();
if (addcourse.Saved) CreateCourseButton(myCourses.Count(), myCourses.Last());
}
The following code is the entry function for the new thread
private void CreateCourseWindow()
{
addcourse = new AddCourse();
addcourse.Activate();
addcourse.Show();
addcourse.Topmost = true;
System.Windows.Threading.Dispatcher.Run();
}
The following code is where i want to terminate the thread
private void Button_Click_2(object sender, RoutedEventArgs e)
{
this.Close();
}
AddCourse is the window 2 class.
First off, don't create multiple UI threads. It creates a real mess that's very hard to deal with. Only ever have on UI thread in your application unless you're sure that you need more, and that you really know what you're doing.
As for this specific case, you don't need to worry about asynchrony, multiple threads, or any of it:
ChildWindow child = new ChildWindow();
this.Hide();
child.ShowDialog();
this.Show();
By using ShowDialog instead of Show you remove all the pesky asynchrony issues.
If you want the parent window visible but not enabled you can remove the show/hide but leave the ShowDialog, which will ensure the parent is disabled.
It is not advised to suspend a window by hanging the thread. What you get is a complete non-responsive window, that doesn't handle any Windows event at all. For example, it will not react to move events, or set cursor events, or other things that you would expect even a disabled window to have. Furthermore, if there are any COM STA objects on this thread they will hang (and sometimes there can be such object even if you didn't explicitly create them).
How are you opening the window from the second thread? It sounds like this thread is running a loop which doesn't terminate when the window is closed. If you post some code it can help.
I want to hide my form while keeping my application running in background.
I've used notifyIcon and it remains always visible.
I've used "this.Hide();" to hide my form but unfortunately my application gets close (no exception).
I am also using threading and this form is on second thread.
Please tell me how can I solve it.
I am also using threading and this form is on second thread.
My crystal ball says that you've used ShowDialog() to show the form. Yes, calling Hide() on a modal dialog will close it. Necessarily so, a modal dialog normally disables all of the windows in the application. If you hide it then there's no way for the user to get back to the program, there are no windows left to activate. That this form runs on another thread otherwise doesn't factor into the behavior.
You'll need to call Application.Run(new SomeForm()) to avoid this. Now it isn't modal and you can hide it without trouble. But really, do avoid showing forms on non-UI threads. There's no reason for it, your main thread is already quite capable.
add the following event handlers for form resize and notify icon click event
private void Form_Resize(object sender, EventArgs e)
{
if (WindowState == FormWindowState.Minimized)
{
this.Hide();
}
}
private void notifyIcon_Click(object sender, EventArgs e)
{
this.Show();
this.WindowState = FormWindowState.Normal;
}
but this is not close you application