Spawn a New Thread to Open a New Window and Close It from a Different Thread

Spawn a new thread to open a new window and close it from a different thread

This is just a quick example. It's a little more robust than the first one I wrote. It eliminates the existing race condition by using p/invoke.

class MainUIThreadForm : Form
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainUIThreadForm());
}

private IntPtr secondThreadFormHandle;

public MainUIThreadForm()
{
Text = "First UI";
Button button;
Controls.Add(button = new Button { Name = "Start", Text = "Start second UI thread", AutoSize = true, Location = new Point(10, 10) });
button.Click += (s, e) =>
{
if (secondThreadFormHandle == IntPtr.Zero)
{
Form form = new Form
{
Text = "Second UI",
Location = new Point(Right, Top),
StartPosition = FormStartPosition.Manual,
};
form.HandleCreated += SecondFormHandleCreated;
form.HandleDestroyed += SecondFormHandleDestroyed;
form.RunInNewThread(false);
}
};
Controls.Add(button = new Button { Name = "Stop", Text = "Stop second UI thread", AutoSize = true, Location = new Point(10, 40), Enabled = false });
button.Click += (s, e) =>
{
if (secondThreadFormHandle != IntPtr.Zero)
PostMessage(secondThreadFormHandle, WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
};
}

void EnableStopButton(bool enabled)
{
if (InvokeRequired)
BeginInvoke((Action)(() => EnableStopButton(enabled)));
else
{
Control stopButton = Controls["Stop"];
if (stopButton != null)
stopButton.Enabled = enabled;
}
}

void SecondFormHandleCreated(object sender, EventArgs e)
{
Control second = sender as Control;
secondThreadFormHandle = second.Handle;
second.HandleCreated -= SecondFormHandleCreated;
EnableStopButton(true);
}

void SecondFormHandleDestroyed(object sender, EventArgs e)
{
Control second = sender as Control;
secondThreadFormHandle = IntPtr.Zero;
second.HandleDestroyed -= SecondFormHandleDestroyed;
EnableStopButton(false);
}

const int WM_CLOSE = 0x0010;
[DllImport("User32.dll")]
extern static IntPtr PostMessage(IntPtr hWnd, int message, IntPtr wParam, IntPtr lParam);
}

internal static class FormExtensions
{
private static void ApplicationRunProc(object state)
{
Application.Run(state as Form);
}

public static void RunInNewThread(this Form form, bool isBackground)
{
if (form == null)
throw new ArgumentNullException("form");
if (form.IsHandleCreated)
throw new InvalidOperationException("Form is already running.");
Thread thread = new Thread(ApplicationRunProc);
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = isBackground;
thread.Start(form);
}
}

C# Open Form in a new Thread or Task?

You can create another UI thread if you simply set the ApartmentState to STA and start another message loop:

Thread _thread = new Thread(() =>
{
Application.Run(new Form());
});
_thread.SetApartmentState(ApartmentState.STA);
_thread.Start();

Note that you wont't be able to display a control that you create on the main thread on this form though. That's why it is generally a bad idea to create more than one UI thread.

How do I open a window on a new thread?

You need to call Show() on the same thread that the window is created on - that's why you are getting the error. Then you also need to start a new Dispatcher instance to get the runtime to manage the window.

private void launchViewerThread_Click(object sender, RoutedEventArgs e)
{
Thread viewerThread = new Thread(delegate()
{
viewer = new SkeletalViewer.MainWindow();
viewer.Show();
System.Windows.Threading.Dispatcher.Run();
});

viewerThread.SetApartmentState(ApartmentState.STA); // needs to be STA or throws exception
viewerThread.Start();
}

See the Multiple Windows/Multiple Threads example at: http://msdn.microsoft.com/en-us/library/ms741870.aspx

Loading window in a new thread

You should do this the other way around when you are waiting for data and stuff to load.

Loading ldd = new Loading();
ldd.SetContentMessage("Loading...");
ldd.ShowDialog();
Thread loadT = new Thread(new ThreadStart() =>
{
//Do stuff here
});
loadT.Start();

Then you can get setup some events and such to either post updates to the loading window, or just leave it as is. You can also either monitor the threads state within the Loading window and close itself when the thread is complete or close the window from the thread.

as an example you could modify Loading to take a Thread as its parameter.

Thread loadT = new Thread(new ThreadStart() => 
{
//Do stuff here
});
Loading ldd = new Loading(loadT);
ldd.ShowDialog();

You can then move the starting of the thread, and monitoring of the thread/closing the window into the Loading class and it can look after itself.

There are 900,000 ways you can do this. You can also use BackgroundWorkers instead of spawning a new Thread, or you can use async/await in .Net 4.5+. Threading like this has been exhaustively done in the past and there should be lots of resources on google to help you in whatever path you decide to take. The important takeaway from this is your window should really be on the UI thread, and your loading should be done on another thread, not the other way around.

WPF open new window on another thread

Use this:

 Task.Factory.StartNew(new Action(() =>
{
//your window code
}), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());

When new thread is created with Current Synchronization context it will be able to update the UI.(when current thread is UI thread)

You can also use dispatcher to execute your code.

 System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(()=>
{
//your window code
}));

Opening new window from an external Thread in Javafx

Perform only the time-consuming work on the background thread. All UI work must be done on the FX Application Thread. (The documentation for Stage explicitly states that "Stage objects must be constructed and modified on the FX Application Thread".) So you should do:

public void login(ActionEvent event) {   

Task<Boolean> loginTask = new Task<Boolean>() {
@Override
protected Boolean call() throws Exception {
return Compte.login(username.getText(), password.getText());
}
};

loginTask.setOnSucceeded(e -> {

if (loginTask.getValue()) {
Parent root = FXMLLoader.load(getClass().getResource("/views/PrincipalFram.fxml"));
Scene scene = new Scene(root);
Stage stage = new Stage();
stage.setScene(scene);
stage.setTitle("My Title");
stage.show();
} else {
//TODO
}
loader.setVisible(false);
});

loginTask.setOnFailed(e -> {
loader.setVisible(false);
});

Thread thread = new Thread(task);
thread.setDaemon(true);
loader.setVisible(true);
thread.start();
}


Related Topics



Leave a reply



Submit