I have need to make a splash screen with a progress bar. My problem is that I cannot link the main form with the splash screen:
public LogIn_Form() {
Thread t = new Thread(new ThreadStart(SplashStart));
t.Start();
Thread.Sleep(5000);
InitializeComponent();
t.Abort();
}
public void SplashStart() {
Application.Run(new Form1());
}
Where I have "Application.Run(new Form1());" it gives me an error under Form1.
This is the splash screen form:
public SplashScreen_Form() {
InitializeComponent();
timer.Start();
}
private void timer_Tick(object sender, EventArgs e) {
this.Opacity += 0.07;
pbrLoad.Increment(1);
if (pbrLoad.Value == 100)
timer.Stop();
}
private void SplashScreen_Form_Load(object sender, EventArgs e) {
this.Opacity = 0;
timer.Enabled = true;
}
Now I need to keep it like that but with no errors.
Related
In an Office Add-In I need to call a WPF which executes a function which may timeout but I want the UI to be responsive to allow the user to click the cancel/close button.
So far my code is the following:
// From the Ribbon
var f = new Forms.CheckConnectivityPopup();
f.doneEvent.WaitOne();
// Get the status from the popup or null if the operation was cancelled
var status = f.status;
if(status != null)
// Continue the execution
--------------------------------
public partial class CheckConnectivityPopup : MetroWindow
{
public readonly BackgroundWorker worker = new BackgroundWorker();
public AutoResetEvent doneEvent = new AutoResetEvent(false);
public Status status = null;
public CheckConnectivityPopup()
{
InitializeComponent();
this.Show();
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.RunWorkerAsync();
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
// displayAndCheck();
status = CheckStatus();
Thread.Sleep(10000); // to simulate the time
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
doneEvent.Set();
this.Close();
}
}
So far the popup is frozen until sleep period is completed.
WaitOne() blocks the current thread. You could replace the AutoResetEvent with a SemaphoreSlim:
public partial class CheckConnectivityPopup : MetroWindow
{
public readonly BackgroundWorker worker = new BackgroundWorker();
public SemaphoreSlim doneEvent = new SemaphoreSlim(0, 1);
public Status status = null;
public CheckConnectivityPopup()
{
InitializeComponent();
this.Show();
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.RunWorkerAsync();
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
//displayAndCheck();
status = CheckStatus();
Thread.Sleep(10000); // to simulate the time
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
doneEvent.Release();
this.Close();
}
}
...that you can await asynchronously:
var f = new Forms.CheckConnectivityPopup();
await f.doneEvent.WaitAsync();
For you to be able to await the WaitAsync() method, you must mark the method where you create the instance of the CheckConnectivityPopup as async:
void async YourMethod() { ... }
If this is not an option for some reason, you could use the ContinueWith method instead:
var f = new Forms.CheckConnectivityPopup();
f.doneEvent.WaitAsync().ContinueWith(_ =>
{
var status = f.status;
if (status != null)
{
//...
}
});
Is it possible to show just splash screen (without showing main form)?
SplashScreen splash;
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
splash = new SplashScreen();
splash.Show();
BackgroundWorker backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork += BackgroundWorker_DoWork;
backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;
backgroundWorker.RunWorkerAsync();
// var mainForm = MainForm();
// Application.Run(layoutForm); // I don't want to call this from here
}
private static void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
splash.Close();
// This never gets called, coz application ended
}
private static void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i <= 100; i++)
{
Thread.Sleep(100);
}
}
You would call your Splash screen from your main form.
public partial class mainform : Form
{
public mainform()
{
InitializeComponent();
}
public mainform_Load(object sender, EventArgs e)
{
this.Visible = false;
using (SplashScreen ss = new SplashScreen())
{
ss.ShowDialog();
SetTheme(ss.LoadedTheme);
this.Visible = true;
}
}
private void SetTheme(Theme theme)
{
//Put your theme setting code here.
}
}
Here's how your SplashScreen code will look:
public partial class SplashScreen : Form
{
public Theme LoadedTheme { get; private set; }
public SplashScreen()
{
InitializeComponent();
}
public void SplashScreen_Load(object sender, EventArgs e)
{
bwSplashScreenWorker.RunWorkerAsync();
}
public void bwSplashScreenWorker_DoWork(object sender, DoWorkEventArgs e)
{
// Load in your data here
LoadedTheme = LoadTheme();
}
public void bwSplashScreenWorker_Completed(object sender, RunWorkerCompletedEventArgs e)
{
DialogResult = DialogResult.OK;
}
}
Now, your application will start, when the mainform is loaded it will hide itself, open the SplashScreen in a blocking manner. The splashscreen will load in your theme data in a background thread and save it into the LoadedTheme property. When the background worker completes it will set the DialogResult to OK which closes the SplashScreen and returns control to mainform_Loaded. At this point you call your SetTheme method passing in the public property LoadedTheme from your SplashScreen. Your SetTheme method sets up your theme and returns back to mainform_Loaded where it sets the mainform to visible.
I have a singletone form that can be opened from a ribbon button or that will check every minute whether it should be open after passing a few conditional checks.
When opening the form from the ribbon button, it works correctly every time.
When opening on the timer, the form does not get rendered correctly, any place a control should be is just displayed as a white rectangle. Screenshots below.
ThisAddIn.cs
using Timer = System.Timers.Timer;
public partial class ThisAddIn
{
private Timer ticker;
private void ThisAddIn_Startup(object sender, System.EventArgs e) {
ticker = new Timer(5 * 60 * 1000);
ticker.AutoReset = true;
ticker.Elapsed += new System.Timers.ElapsedEventHandler(checkForOverdue);
ticker.Start();
}
private void checkForOverdue(object sender, System.Timers.ElapsedEventArgs e)
{
bool overdue = false;
foreach (Reminder reminder in reminders)
{
DateTime now = DateTime.Now;
if (reminder.time <= now)
{
overdue = true;
break;
}
}
if (overdue)
{
RemindersList form = RemindersList.CreateInstance();
if (form != null)
{
form.Show();
}
}
}
}
Ribbon.cs
public partial class Ribbon
{
private void reminderListButton_Click(object sender, RibbonControlEventArgs e)
{
RemindersList form = RemindersList.CreateInstance();
if (form != null)
{
form.Show();
}
}
}
RemindersList.cs
public partial class RemindersList : Form
{
private static RemindersList _singleton;
private RemindersList()
{
InitializeComponent();
this.FormClosed += new FormClosedEventHandler(f_formClosed);
}
private static void f_formClosed(object sender, FormClosedEventArgs e)
{
_singleton = null;
}
public static RemindersList CreateInstance(List<Reminder> rs)
{
if (_singleton == null)
{
_singleton = new RemindersList(rs);
_singleton.Activate();
// Flash in taskbar if not active window
FlashWindow.Flash(_singleton);
return _singleton;
}
else
{
return null;
}
}
}
EDIT - SOLUTION
Per sa_ddam213's answer, I changed out the System.Timers.Timer for a Windows.Forms.Timer and it's now working just how I wanted.
Code changes:
ThisAddIn.cs
using Timer = System.Windows.Forms.Timer;
public partial class ThisAddIn {
private void ThisAddIn_Startup(object sender, System.EventArgs e) {
ticker = new Timer();
ticker.Interval = 5 * 60 * 1000;
ticker.Tick += new EventHandler(checkForOverdue);
ticker.Start();
}
// Also needed to change the checkForOverdue prototype as follows:
private void checkForOverdue(object sender, EventArgs e)
}
You can't touch UI controls/elements with any other thread than the UI thread, in your case the System.Timer is running on another thread and the window will never open
Try switching to a Windows.Forms.Timer
Or invoke the call back to the UI thread.
private void checkForOverdue(object sender, System.Timers.ElapsedEventArgs e)
{
base.Invoke(new Action(() =>
{
/// all your code here
}));
}
I suspect that the timer event handler is not launched on the UI thread, which could cause all sorts of problems. I would check that first and ensure that the UI stuff is actually done on the UI thread.
My form is going to run some code that might take a while to execute. I would like to display a "please wait" message while the operation is running on the background.
I'd like to have that message in a form, one that I can control its visibility, and also its text, from other forms.
I'd also like it to be set to start in the Program.cs file.
My code, so far:
namespace KAN
{
public partial class prosze_czekac : Form
{
public prosze_czekac()
{
InitializeComponent();
}
private delegate void OffVisible();
public void Wylacz()
{
if (this.InvokeRequired)
this.Invoke(new OffVisible(Wylacz));
else
this.Visible = false;
}
delegate void SetTextCallback(string text);
public void ZmienTekst(string text)
{
if (this.InvokeRequired)
{
//SetTextCallback d = new SetTextCallback(this.ZmienTekst);
Invoke(new SetTextCallback(this.ZmienTekst), text);
//Invoke(d, new object[] { text });
}
else
{
this.Visible = true;
this.Text = text;
this.lblKomunikat.Text = text;
this.Update();
}
}
}
}
I do not know how to run a form, how to create an instance and as editing text. All this in any form, any thread.
Is the above code is correct and how to use it to make it properly?
How am I so ready form "please wait" I would like to turn it on now in the initial class (Program.cs). Use it in any form design.
Sample code, do not know if correct:
namespace KAN
{
static class Program
{
public static prosze_czekac PleaseWait;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Thread thread = new Thread(new ThreadStart(PleaseWait.Show());
PleaseWait.ZmienTekst("Please wait... Running the program");
// long operation
PleaseWait.Wylacz();
Application.Run(new main());
}
}
}
namespace KAN
{
public partial class main: Form
{
public main()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// examples of long task in another form
for (int i = 0; i < 5; i++)
{
Program.PleaseWait.ZmienTekst((i + 1).ToString());
System.Threading.Thread.Sleep(1000);
}
Program.PleaseWait.Wylacz();
}
}
}
The first time I ask a question, please bear with me.
PS
"Wylacz" is "exit" (void) and is meant to "hide" so that every time you do not initiate the form.
"prosze_czekac" is "please wait".
Use the BackgroundWorker. The following code assumes, you have a button 'button1' in your form, which executes the worker, which starts the long running task on a different thread:
BackgroundWorker _worker;
// button click starts the execution of the lung running task on another thread
private void button1_Click(object sender, EventArgs e)
{
label1.Visible = true; // show the label "please wait"
_worker.RunWorkerAsync();
}
private void Form1_Load(object sender, EventArgs e)
{
// initialize worker
_worker = new BackgroundWorker();
_worker.DoWork += new DoWorkEventHandler(worker_DoWork);
_worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_worker_RunWorkerCompleted);
}
// executes when long running task has finished
void _worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// hide the label
label1.Visible = false;
}
// is called by 'RunWorkerAsync' and executes the long running task on a different thread
void worker_DoWork(object sender, DoWorkEventArgs e)
{
// long running task (just an example)
for (int i = 0; i < 1000000000; i++)
{
}
}
I am trying to run a function in a different class than the dispatcher through a backgroundworker and have it update the progress on every iteration. I am getting no errors and the backgroundworker is functioning properly, but my textbox never updates...
public partial class MainWindow : Window
{
public BackgroundWorker worker = new BackgroundWorker();
public MainWindow()
{
InitializeComponent();
worker.WorkerReportsProgress = true;
worker.DoWork += new DoWorkEventHandler(workerDoWork);
worker.ProgressChanged += new ProgressChangedEventHandler(workerProgressChanged);
}
private void myButtonClick(object sender, RoutedEventArgs e)
{
worker.RunWorkerAsync();
}
void workerDoWork(object sender, DoWorkEventArgs e)
{
yv_usfm.convert(worker);
}
void workerProgressChanged(object sender, ProgressChangedEventArgs e)
{
myTextBox.Text = "some text";
}
}
public class yv_usfm
{
public static void convert(BackgroundWorker worker)
{
int i = 1;
while (i < 100)
{
worker.ReportProgress(i);
i++;
}
}
}
What makes you say the BackgroundWorker is functioning properly? I see no call to worker.RunWorkerAsync(), and without that it will never start.
You're not starting the worker!
worker.RunWorkerAsync();
Try This:
void DoWork(...)
{
YourMethod();
}
void YourMethod()
{
if(yourControl.InvokeRequired)
yourControl.Invoke((Action)(() => YourMethod()));
else
{
//Access controls
}
}
Hope This help.