When I use a button on a form for Winforms to open a window made in XAML the first time it works with no issues, then I close the window and re-click the button, but on the InitializeComponent() for the window being created I get an exception with the message, "The Application object is being shut down".
//code on button press is this
var rs = new RestoreSettings();
rs.Show();
I have tried hosting it as a user control inside an element host still the same issue.
In a normal application both the WinForms and WPF environment is kickstarted by an Application type, which is typically called from the Main method.
Here this does not happen for the WPF environment, which causes problems. If you want to show a WPF window from a WinForms application you need to boot up the dispatcher. Best to do this in a new thread so it can be shut down as many times as you want:
private void ShowWpfWindow()
{
// This delegate is executed in new thread
ThreadStart showWindow = () =>
{
var window = new RestoreSettingsWindow(); // your window to show
// making sure that the thread can exit when the window is closed
window.Closed += (sender, e) => Dispatcher.InvokeShutdown();
window.Show();
// Starts the dispatcher in the new thread and does not let the thread exit.
// This call is returned when the window is closed (due to the Closed event handler)
System.Windows.Threading.Dispatcher.Run();
};
// Creating and starting an STA thread for the WPF window
Thread wpfThread = new Thread(showWindow);
wpfThread.SetApartmentState(ApartmentState.STA);
wpfThread.Priority = ThreadPriority.Normal;
wpfThread.Start();
}
Related
From my main WinForm application window, I want to simultaneously open multiple modeless dialogs. When all dialog windows are opened, I will raise some events and the event handlers on individual open dialogs are supposed to take necessary actions on those events. Since user wants access to the main form all the time, I cannot open these windows as modal dialogs.
I have written following code.
With this code, the dialog windows are opened but they are immediately closed too. What's wrong with the code? Why windows don't remain open?
private async void buttonOpenWindows_Click(object sender, EventArgs e)
{
Task[] tasks = new Task[]
{
Task.Factory.StartNew(CreateWindow),
Task.Factory.StartNew(CreateWindow),
Task.Factory.StartNew(CreateWindow),
Task.Factory.StartNew(CreateWindow)
};
await Task.WhenAll(tasks);
// Raise necessary events when all windows are loaded.
}
private async Task CreateWindow()
{
// A refernce to main form is passed to the Window because all Windows will be subsribing to some events raised by the main form.
var window = new Window1(this);
window.Show();
}
What is happening:
private async Task CreateWindow()
{
// A refernce to main form is passed to the Window because all Windows will be subsribing to some events raised by the main form.
var window = new Window1(this);
window.Show();
}
This creates a new window, owned by the first available thread in the system. As there is no more blocking code to run, the Task finishes successfully, and so the Window is closed/disposed.
If you want the Window to continue to be opened, you need to open it in your main thread.
Not sure what you are expecting to benefit from by opening the Windows in an async manner, though.
I have a WPF application using PRISM. I have a login screen and on successfuly logging in a new view containing a TileListView with many items appears. This needs over 10 seconds to render because control has to calculate a lot etc. All this uses the UI thread by standard behaviour, because rendering in WPF is done in UI thread. Is it possible to display a WaitControl like a spinner or just a simple animation in seperate window or something like this? Now to animation stops at the time, the control is rendered in UI Thread.
You could create a new window that launches in a separate thread. Please refer to the following blog post for an example of how to do this.
Launching a WPF Window in a Separate Thread: http://reedcopsey.com/2011/11/28/launching-a-wpf-window-in-a-separate-thread-part-1/
Then you just start this thread that displays the window just after you have validated the credentials and just before your heavy rendering is about to begin.
This is probably the best thing you can do and it should also be a pretty easy thing to implement.
Edit - Including code from above link to be recorded for posterity:
using System.Threading;
using System.Windows.Threading;
void LoadWindowInThread()
{
Thread newWindowThread = new Thread(new ThreadStart(() =>
{
// Create our context, and install it:
SynchronizationContext.SetSynchronizationContext(
new DispatcherSynchronizationContext(
Dispatcher.CurrentDispatcher));
// Create and configure the window
Window1 tempWindow = new Window1();
// When the window closes, shut down the dispatcher
tempWindow.Closed += (s, e) =>
Dispatcher.CurrentDispatcher.BeginInvokeShutdown(DispatcherPriority.Background);
tempWindow.Show();
// Start the Dispatcher Processing
Dispatcher.Run();
}));
newWindowThread.SetApartmentState(ApartmentState.STA);
// Make the thread a background thread
newWindowThread.IsBackground = true;
// Start the thread
newWindowThread.Start();
}
you can use SplashScreen to display untill the background process is completed. Refer this Splash Screen in WPF
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 have a WPF application. The main window of this application has a button. I am opening a WinForms modal dialog in a separate thread when this button is clicked. The trouble I am having is that the dialog does not behave like a modal i.e it is still possible to switch focus to the main window, whereas, I require to allow focus on the newly opened dialog and it should not be possible to select the main window.
Note: I cannot move the modalDialog.ShowDialog(); outside of the delegate because the dialog form creates controls dynamically and this means that these controls must remain on the thread that it was created. To be more clear, if I move the modalDialog.ShowDialog(); outside I will get an exception like so:
Cross-thread operation not vaild: Control 'DynamicList' accessed from a thread other than the one it was created on.
Any ideas as to how I might make the form behave as a modal?
Here is the code:
private void button1_Click(object sender, RoutedEventArgs e)
{
DoSomeAsyncWork();
}
private void DoSomeAsyncWork()
{
var modalDialog = new TestForm();
var backgroundThread = new Thread((
delegate()
{
// Call intensive method that creates dynamic controls
modalDialog.DoSomeLongWaitingCall();
modalDialog.ShowDialog();
}
));
backgroundThread.Start();
}
You should always create controls on the UI thread. If you do that, calling ShowDialog() through Dispatcher should work.
I have a form in a Windows form application that I want to display on top of a main form, close it, and then immediately show a dialog box using MessageBox.Show(). But the first form is still showing when the message box is shown, and it does not disappear until I click OK on the message box. I tried waiting to show the message box in an event handler for the form's VisibleChanged event and even calling Refresh() on both the form and the main form. Is there a way I can determine when the first form has fully disappeared before displaying the message box?
Edit:
Here is some code that demonstrates how the forms are being shown.
static class Program
{
// The main form is shown like this:
static void Main()
{
Application.Run(new MainForm());
}
}
public class Class1
{
// _modalForm is the first form that is displayed that won't fully go away
// when it is closed.
ModalForm _modalForm;
BackgroundWorker _worker;
public Class1()
{
_modalForm = new ModalForm();
_worker = new BackGroundWorker();
_worker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted
}
public void Method1()
{
_worker.RunWorkerAsync();
// The first form is shown.
_modalForm.ShowDialog();
}
// This code runs in the UI thread.
void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
_modalForm.VisibleChanged += new EventHandler(_modalForm_visibleChanged);
_modalForm.Close();
}
void _modalForm_visibleChanged(object sender, EventArgs e)
{
// When the message box is shown, the other form is still visible
// and remains so until I click OK.
MessageBox.Show("The other form was just closed.");
// Note: I originally tried to use the FormClosed event instead of
// VisibleChanged. Then I tried Deactivate, in attempt to use an event
// that occurred later thinking that might do the trick. VisibleChanged
// is the latest event that I found.
//
}
I'll guess that you are running your code on Windows XP or Vista/Win7 with Aero turned off. Closing a form does not make the pixels on the screen disappear instantly. The Windows window manager sees that the window for the form got destroyed and that this revealed parts of other windows underneath it. It will deliver a WM_PAINT message to let them know that they need to repaint the parts of the window that got revealed.
This will not work properly if one or more of those windows isn't actively pumping a message loop. They can't see the WM_PAINT message. They won't repaint themselves, the pixels of the closed form will remain on the screen.
Find out why these windows are not responding. Hopefully it is your window and the debugger can show you what the UI thread is doing. Make sure it isn't blocking on something or stuck in a loop.
After seeing the edit: there's indeed blocking going on, of a different kind. The MessageBox.Show() call is modal, it prevents the VisibleChanged event from completing. That delays the closing of the form.
Use System.Diagnostics.Debug.WriteLine() or Console.WriteLine() to get diagnostics in a Window Forms app. You'll see it in the Output window. Or simply use a debugger breakpoint.
The Form.FormClosed event is raised when the form completes closing. At this point, all Form.FormClosing event handlers have been run, and none of them canceled the close.
Form.FormClosed replaced Form.Closed (which is deprecated) in the .NET 2.0 framework.
Form.Closed Event
http://msdn.microsoft.com/en-us/library/system.windows.forms.form.closed(VS.71).aspx