Load another window in background; when rendered, close the parent window - c#

I have been trying to load another window in background within a window; parent window acts as a splash screen in my case.
InitWindow I = null;
public InitWindow()
{
InitializeComponent();
I = this;
Thread T = new Thread(() =>
{
MainWindow M = new MainWindow();
M.Show();
M.ContentRendered += M_ContentRendered;
System.Windows.Threading.Dispatcher.Run();
M.Closed += (s, e) => M.Dispatcher.InvokeShutdown();
}) { IsBackground = true, Priority = ThreadPriority.Lowest };
T.SetApartmentState(ApartmentState.STA);
T.Start();
}
void M_ContentRendered(object sender, EventArgs e)
{
I.Close();
}
Everything else works fine but it throws an Invalid Operation Exception at:
I.Close();
the calling thread cannot access this object because a different thread owns it.
1) How do I switch/sync thread?
2) Is there a better workaround?

Changed code to:
InitWindow I = null;
Thread C = null;
public InitWindow()
{
InitializeComponent();
I = this;
C = Thread.CurrentThread;
Thread T = new Thread(() =>
{
MainWindow M = new MainWindow();
M.Show();
M.ContentRendered += M_ContentRendered;
System.Windows.Threading.Dispatcher.Run();
M.Closed += (s, e) => M.Dispatcher.InvokeShutdown();
}) { IsBackground = true, Priority = ThreadPriority.Lowest };
T.SetApartmentState(ApartmentState.STA);
T.Start();
}
void M_ContentRendered(object sender, EventArgs e)
{
// Making the parent thread background
C.IsBackground = true;
// foreground the current thread
Thread.CurrentThread.IsBackground = false;
// Abort the parent thread
C.Abort();
}
Works fine as of now, but I don't think it's a reliable solution.

Related

Enable/Disable buttons while thread is working

I have a button that starts two threads
private void CrawdBtn_Click(object sender, EventArgs e)
{
CrawdBtn.Enabled = false;
t = new Thread(AddLinksToList);
b = new Thread(EnqueueFromList);
t.Start();
b.Start();
}
and there are another buttons to pause, Resume, Stop those threads
My question is how can I disable (pause, Resume, Stop) buttons while the threads are working and re enable Crawl after the threads finished
Here is how you could start a Thread and have a way to await its completion:
public static Thread CreateAwaitableThread(Action action, out Task threadCompletion)
{
var tcs = new TaskCompletionSource<bool>();
threadCompletion = tcs.Task;
return new Thread(() =>
{
try
{
action();
}
finally
{
tcs.SetResult(true);
}
});
}
This method returns the newly created Thread, and also a Task that will be completed when the Thread is completed. You could use it like this:
private async void CrawdBtn_Click(object sender, EventArgs e)
{
CrawdBtn.Enabled = false;
Thread t1 = CreateAwaitableThread(AddLinksToList, out var t1c);
Thread t2 = CreateAwaitableThread(EnqueueFromList, out var t2c);
t1.Start();
t2.Start();
await Task.WhenAll(t1c, t2c);
CrawdBtn.Enabled = true;
}
In case of an exception the error will not be propagated through the Task. It is assumed that the delegates already include error handling logic. If not, an unhandled exception will occur as usual.
To solve your problem you can make a thread to check the ThreadState of thread t and thread b
private void btnstart_Click(object sender, EventArgs e)
{
t = new Thread(AddLinksToList);
b = new Thread(EnqueueFromList);
t.Start();
b.Start();
if (threadchecker == null)//this if determines Whether it's the first time or not
{
threadchecker = new Thread(() => ChekingStateOfThreads());
threadchecker.IsBackground = true;
threadchecker.Start();
}
}
Since the thread wants to check the ThreadState of those threads it should always run.
and This is ChekingStateOfThreads
private void ChekingStateOfThreads()
{
while (true)
{
Thread.Sleep(1000);
if (t.ThreadState == ThreadState.Stopped)
{
this.Invoke(new Action(() =>
{
btnpause.Enabled = btnstart.Enabled = false;
btnresume.Enabled = btnstop.Enabled = true;
}));
}
else if (t.ThreadState == ThreadState.Running)
{
this.Invoke(new Action(() =>
{
btnstart.Enabled = btnresume.Enabled = false;
btnpause.Enabled = btnstop.Enabled = true;
}));
}
else if (t.ThreadState == ThreadState.Aborted)
{
this.Invoke(new Action(() =>
{
btnstart.Enabled = true;
btnpause.Enabled = btnresume.Enabled = btnstop.Enabled = false;
}));
}
else if (t.ThreadState == ThreadState.Suspended)
{
this.Invoke(new Action(() =>
{
btnpause.Enabled = btnstart.Enabled = false;
btnresume.Enabled = btnstop.Enabled = true;
}));
}
}
}
The concept of function is pretty simple. Each 1 second the thread is check the state of thread t.
See Why use Invoke on Controls in .net? to figure out why should we use INVOKE.
To abort the threadchecker just use the Form_closing Event
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
threadchecker.Abort();
}

Accessing GUI window created by a Caliburn.Micro application on a background thread?

I've got a caliburn.micro WPF application, and I'm launching it from F# with a call to this function:
public void LaunchGUI()
{
if (_guiWindow == null)
{
var windowThread = new Thread(() =>
{
try
{
// Create our context, and install it:
SynchronizationContext.SetSynchronizationContext(new DispatcherSynchronizationContext(Dispatcher.CurrentDispatcher));
AppBootstrapper.Initialize();
var app = new App();
app.InitializeComponent();
//guiWindow = app.MainWindow;
//// When the window closes, shut down the dispatcher
//guiWindow.Closed += (s, e) =>
// Dispatcher.CurrentDispatcher.BeginInvokeShutdown(DispatcherPriority.Background);
//guiWindow.Closed += (s, e) =>
// guiWindow = null;
//guiWindow.WindowState = WindowState.Minimized;
//guiWindow.Show();
//guiWindow.WindowState = WindowState.Normal;
//guiWindow.Activate();
// Start the Dispatcher Processing
Dispatcher.Run();
}
catch (Exception e)
{
LogMessage("error in gui thread: " + e);
//guiWindow.Close();
//guiWindow = null;
}
});
windowThread.SetApartmentState(ApartmentState.STA);
windowThread.IsBackground = true;
windowThread.Start();
}
else
{
_guiWindow.WindowState = WindowState.Minimized;
_guiWindow.Show();
_guiWindow.WindowState = WindowState.Normal;
_guiWindow.Activate();
}
}
}
The issue is I need to have a reference to the main window so I can keep track of whether it's still open, etc., but it is always null (hence the commented code). Note this works fine when running a "normal" MVVM app, and initializing it in a similar way:
public void ShowGui()
{
if (guiWindow == null)
{
var windowThread = new Thread(() =>
{
try
{
// Create our context, and install it:
SynchronizationContext.SetSynchronizationContext(
new DispatcherSynchronizationContext(
Dispatcher.CurrentDispatcher));
guiWindow = new MainWindow();
// When the window closes, shut down the dispatcher
guiWindow.Closed += (s, e) =>
Dispatcher.CurrentDispatcher.BeginInvokeShutdown(DispatcherPriority.Background);
guiWindow.Closed += (s, e) =>
guiWindow = null;
guiWindow.WindowState = WindowState.Minimized;
guiWindow.Show();
guiWindow.WindowState = WindowState.Normal;
guiWindow.Activate();
// Start the Dispatcher Processing
Dispatcher.Run();
}
catch (Exception)
{
try
{
guiWindow.Close();
}
catch (Exception)
{
throw;
}
guiWindow = null;
}
});
windowThread.SetApartmentState(ApartmentState.STA);
windowThread.IsBackground = true;
windowThread.Start();
}
else
{
guiWindow.WindowState = WindowState.Minimized;
guiWindow.Show();
guiWindow.WindowState = WindowState.Normal;
guiWindow.Activate();
}
}
My question is how do I get access to the main window created?
// you get get the application main windows like this:
var _guiWindow = Application.Current.MainWindow as MainWindow;

How to check every 30seconds with dispatchertimer without affect the UI in c#?

I hav tried the below code for checking reports from server in every 30seconds,but after 30seconds tick,The application hangs for several seconds.How to avoid the Hanging problem.
The below code am tried,what change want to given in this?
System.Windows.Threading.DispatcherTimer dispatcherTimer2 = new System.Windows.Threading.DispatcherTimer();
dispatcherTimer2.Tick += new EventHandler(dispatcherTimer2_Tick);
dispatcherTimer2.Interval = new TimeSpan(0, 0, 30);
Public void dispatcherTimer2_Tick(object sender, EventArgs e)
{
dispatcherTimer2.start();
//code for function call autoreport();
}
DispatcherTimer callback is executed on main UI thread and blocks it.
Use System.Threading.Timer and if you need to update user interface from timer callback use one of
Dispatcher.Invoke
overloads.
In code something like this
public partial class MainWindow : Window
{
System.Threading.Timer timer;
public MainWindow()
{
InitializeComponent();
timer = new System.Threading.Timer(OnCallBack, null, 0, 30 * 1000);
}
private void OnCallBack(object state)
{
//code to check report
Dispatcher.Invoke(() =>
{
//code to update ui
this.Label.Content = string.Format("Fired at {0}", DateTime.Now);
});
}
}
var timer = new System.Threading.Timer(
delegate
{
//--update functions here (large operations)
var value = Environment.TickCount;
//--run update using interface thread(UI Thread)
//--for WinForms
Invoke(
new Action(() =>
{
//--set the value to UI Element
}));
//--for WPF
Dispatcher.Invoke(
new Action(() =>
{
//--set the value to UI Element
}), null);
});
var period = TimeSpan.FromSeconds(30);
timer.Change(period, period);
I hope it helps.
This is worked for me
public Form1()
{
InitializeComponent();
var timer = new System.Timers.Timer(500);
// Hook up the Elapsed event for the timer.
timer.Elapsed += timer_Elapsed;
timer.Enabled = true;
}
void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
Invoke(
new Action(() =>
{
label1.Text += "Test Label";
Application.DoEvents();
}));
}

WPF/MVVM - Is there is any event fired after GUI get updated

In my application I used to add a lot of text in Richtextbox. It takes a lot of time, so i have added a progress bar. I need to close that as soon as GUI is updated. Is there is any to to catch after GUI is updated.
I have tried with App.Current.MainWindow.IsLoaded == true, but it seems even the gui is not updated, but MainWindow.IsLoaded property is true for main window.
Herewith the code for the same.
private void OnWorkerMethodstart()
{
pbw = new ProgressBarWindow();
pbw.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
new Action(
delegate()
{
pbw.ShowDialog();
}
));
}
private void OnWorkerMethodStart()
{
ThreadStart tStart = new ThreadStart(OnWorkerMethodstart);
t = new Thread(tStart);
t.SetApartmentState(ApartmentState.STA);
t.Start();
this.OpenW();
BackgroundWorker _BackgroundWorker1 = new BackgroundWorker();
_BackgroundWorker1.DoWork += new DoWorkEventHandler(
delegate(object o, DoWorkEventArgs args)
{
this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
new Action(
delegate()
{
DateTime da = DateTime.Now.AddMinutes(30);
MainWindow mw;
while (DateTime.Now != da)
{
mw = new MainWindow();
//if (mw.Editor.Workflow.Steps.Count > 1)
if (App.Current.MainWindow.IsLoaded == true)
{
t.Abort();
break;
}
else
{
//Thread.Sleep(1000);
}
mw = null;
}
}
));
});
_BackgroundWorker1.RunWorkerAsync();
}

STA Thread is not loading the Main Window in WPF

I am loading MainWindow in App_Startup (). I wanted to show the progress bar while loading the window. But it is not working :
void App_Startup(object sender, StartupEventArgs e)
{
Thread bootStrapThread = new Thread(new ThreadStart(runBootStrapProcess));
bootStrapThread.SetApartmentState(ApartmentState.STA);
bootStrapThread.IsBackground = true;
bootStrapThread.Start();
_loadingProgressBar = new loadingProgressBar();
_loadingProgressBar.ShowDialog();
}
I want to load the window from thread :
void runBootStrapProcess()
{
MetadataReader mr = new MetadataReader();
if (currentVersionNo.Equals(remoteVersionNo))
{
Application.Current.Shutdown();
}
else
{
MainWindow mw = new MainWindow();
mw.Show();
}
_loadingProgressBar.ShouldCloseNow = true;
}
You can try this:
void runBootStrapProcess() {
MetadataReader mr = new MetadataReader();
if (currentVersionNo.Equals(remoteVersionNo)) {
Application.Current.Shutdown();
} else {
System.Windows.Application.Current.Dispatcher.BeginInvoke(
new Action(
() => {
MainWindow mw = new MainWindow();
mw.Show();
}));
}
_loadingProgressBar.ShouldCloseNow = true;
}
You basically from the thread when you want to show the window send it to the main application thread. This thus stops the application from closing down when the thread exits since the MainWindow is Shown from the main thread.
I suspect the window is missing the message pump since the WPF Application class with its Dispatcher is running on a different STA Thread

Categories

Resources