This question already has answers here:
How to build splash screen in windows forms application?
(13 answers)
Closed 9 years ago.
I was wondering how to make a SplashScreen in C#. I looked around StackOverflow but found nothing useful, can you help me please? I already have 1 form filled with stuff, I just need some simple instructions on how to:
Make a new form appear before my main form
Make the SplashScreen disappear and the main form appear after a few seconds (maybe three)
I don't need an animated splashscreen.
Thanks in advance!
Just ask if you need any code samples from me :)
Here is an example of a splashscreen - I have used in one of my projects - that uses multithreading:
namespace WindowsForm1
{
public enum SplashTypeOfMessage
{ Success,
Warning,
Error
}
public partial class SplashForm : Form
{
static SplashForm _splashForm = null;
static Thread _splashThread = null;
public static object locker = new object();
public static bool WaitPlease = true;
private SplashForm()
{
InitializeComponent();
lblLoading.Text = "Please wait Loading";
}
public static void ShowSplashScreen()
{
if (_splashForm != null)
return;
_splashThread = new Thread(new ThreadStart(SplashForm.ShowSplash));
_splashThread.IsBackground = true;
_splashThread.SetApartmentState(ApartmentState.STA) ;
_splashThread.Start();
}
public static void ShowSplash()
{
if (_splashForm==null)
{
_splashForm = new SplashForm();
_splashForm.blueLoaderBar1.StartAnimation();
}
_splashForm.TopMost = true;
_splashForm.Show();
lock (SplashForm.locker)
{
WaitPlease = false;
}
Application.Run(_splashForm);
}
delegate void CloseSplashHandler(SplashTypeOfMessage typeOfMessage, string message,bool itWasRinvoked);
public static void CloseSplash(SplashTypeOfMessage typeOfMessage,string message,bool itWasrinvoked)
{
CloseSplashHandler closeSpalshHandler = new CloseSplashHandler(CloseSplash);
bool launched=false;
while (!launched && !itWasrinvoked)
{
lock (SplashForm.locker)
{
if (!SplashForm.WaitPlease)
{
launched = true;
}
}
}
if (_splashForm!=null && _splashThread!=null )
{
if (_splashForm.InvokeRequired)
{
_splashForm.Invoke(closeSpalshHandler,new object[] {typeOfMessage,message,true});
}
else
{
switch (typeOfMessage)
{
case SplashTypeOfMessage.Warning:
break;
case SplashTypeOfMessage.Error:
MessageBox.Show("Error");
break;
default:
break;
}
_splashForm.Close();
_splashThread = null;
}
}
}
}
}
Here is how you can call it:
SplashForm.ShowSplashScreen();
This is how you can close the splash screen:
SplashForm.CloseSplash(typeOfMessage ,string.Empty,false);
Related
I've got a WPF RichTextBox that I'd like to get working as a log output for the app.
I have a static class Log with method to write to the WPF RTB. Of course, this doesnt work when a background thread call the method.
I've tried using BeginInvoke, which works until the app gets closed throwing an error 'System.Windows.Application.Current.get returned null'
What is the proper approach to updating WPF RichText from other threads. And further, I dont think this background thread is disposing properly, any recommendations?
public partial class MainWindow : Window
{
Worker worker = new Worker();
public MainWindow()
{
InitializeComponent();
Log.rtb_control = rtbLog; // pass RTB ref to Log
worker.Start();
}
}
public static class Log
{
public static RichTextBox rtb_Control;
public static void Add(string Text)
{
App.Current.Dispatcher.BeginInvoke((Action)(() =>
{
rtb_Control.AppendText($"{Text}\r");
}
}
}
public class Worker
{
bool _Enabled = false;
public Worker()
{
_Manager = new Thread(new ThreadStart(Thread_Manager));
_Manager.Start();
}
public void Start()
{
_Enabled = true;
}
void Thread_Manager()
{
while(true)
{
if(_Enabled) { Log.Add("Inside Thread"); }
Thread.Sleep(10000);
}
}
}
I've been trying to get this little IRC program working but for some reason I'm having issues with VS and cross threading. I'm not sure if I'm not doing it the proper way or what. Here are the parts causing the issue.
Main Thread:
public partial class MainUI : Form
{
private static IRC irc = new IRC();
public MainUI()
{
InitializeComponent();
}
public static void StartIRC()
{
irc.Start();
}
}
IRC Thread:
class IRC
{
private Thread ircThread;
private bool _running = true;
private NetworkStream stream;
private StreamWriter writer;
private StreamReader reader;
private TcpClient irc;
public IRC(){
ircThread = new Thread(new ThreadStart(Run));
ircThread.IsBackground = true;
}
public void Run(){
while (_running) {
parseInStream(reader.ReadLine());
}
}
public void Start()
{
ircThread.Start();
}
private void parseInStream(String inText)
{
String[] text = inText.Split(' ');
String name;
String message;
if (text[1].Equals("PRIVMSG")) {
name = capsFirstChar(getUser(inText));
message = inText.Substring(inText.IndexOf(":", 1) + 1);
sendToChatBox(capsFirstChar(name) + ": " + message, Color.Black);
}
else if (text[1].Equals("JOIN")) {
name = getUser(inText);
sendToChatBox(capsFirstChar(name) + " has joined the channel.", Color.LimeGreen);
}
else if (text[1].Equals("PART")) {
name = getUser(inText);
sendToChatBox(capsFirstChar(name) + " has left the channel.", Color.Red);
}
}
public void sendToChatBox(String text, Color color)
{
//Trying to send the text to the chatbox on the MainUI
//Works if the MainUI.Designer.cs file has it set to static
if (MainUI.txtMainChat.InvokeRequired) {
MainUI.txtMainChat.Invoke((MethodInvoker)delegate() {
sendToChatBox(text, color);
});
}
else {
MainUI.txtMainChat.SelectionColor = color;
MainUI.txtMainChat.AppendText(text);
}
}
private String getUser(String msg)
{
String[] split = msg.Split('!');
user = split[0].Substring(1);
return capsFirstChar(user);
}
private String capsFirstChar(String text)
{
return char.ToUpper(text[0]) + text.Substring(1).ToLower();
}
}
The only way I am able to get it to work is if I enter the MainUI.Designer.cs file and change the textbox to static and then change everything from this.txtMainChatto MainUI.txtMainChat.
My main problem is that when I make any changes on the visual side all the things labeled static or things named MainUI are deleted. I'm trying to figure out what I need to do to keep this from happening. Am I doing it the right way, or is there a better way? I tried using a background worker but it was using a lot of processing power to work that way for some reason.
I've looked around the web and can't seem to find out how one might relate to my setup. I see people calling a thread from the main thread and then sending things from the main thread to the thread it called but not the other way around. There is nothing else being written to the text box so there won't be an issue with it being used by two threads at the same time.
On my main UI thread I passed in "this" so I could reference the main window from my IRC Class. MainUI.txtMainChat
irc = new IRC(this);
Then in my IRC class
MainUI main;
public IRC(MainUI main){
this.main = main;
ircThread = new Thread(new ThreadStart(Run));
ircThread.IsBackground = true;
}
Then I was able to Change
//MainUI.txtMainChat to
main.txtMainChat
Like Cameron said, Though I know I was told it's not the best approach it gets me started.
Your designer file is rebuilt every time you change your UI in the designer.
You'll need to pass your MainUi to your IRC class, or give it an abstraction of it using an interface (best option).
public interface IMainUI
{
void AddText(string text, Color color);
void UiThread(Action code);
}
public class MainUI : IMainUI
{
// Whatever else
public void AddText(string text, Color color)
{
UiThread( () =>
{
// Same code that was in your Irc.SendToChatBox method.
});
}
public void UiThread(Action code)
{
if (InvokeRequired)
{
BeginInvoke(code);
return;
}
code.Invoke();
}
}
public class IRC
{
IMainUI _mainUi;
//Other properties, and fields
public IRC(IMainUI mainUi)
{
this._mainUi = mainUi;
// Other constructor stuff.
}
// Other logic and methods
}
This question already has answers here:
How can I make the cursor turn to the wait cursor?
(11 answers)
Closed 9 years ago.
I have a Windows Forms application, in my application i load files into a list box and sometimes this could take few seconds so in this time i want to show "Spinning Wheel” and i found this Gif: http://www.ajaxload.info/
is it possible to add it to my application while my application is busy over the controllers ?
Yes
Found some old code from a project where I had it.
Edited out a few things, you should be able to get it working easily.
Invoke it:
GuiCursor.WaitCursor(() => { yourclass.DoSomething(); });
The class
internal class GuiCursor
{
private static GuiCursor instance = new GuiCursor();
private GuiCursor() { }
static GuiCursor() { }
internal static void WaitCursor(MethodInvoker oper)
{
if (Form.ActiveForm != null && !Thread.CurrentThread.IsBackground)
{
Form myform = Form.ActiveForm;
myform.Cursor = Cursors.WaitCursor;
try
{
oper();
}
finally
{
myform.Cursor = Cursors.Default;
}
}
else
{
oper();
}
}
internal static void ToggleWaitCursor(Form form, bool wait)
{
if (form != null)
{
if (form.InvokeRequired)
{
form.Invoke(new MethodInvoker(() => { form.Cursor = wait? Cursors.WaitCursor : Cursors.Default; }));
}
else
{
form.Cursor = wait ? Cursors.WaitCursor : Cursors.Default;
}
}
}
internal static void Run(Form form)
{
try
{
Application.Run(form);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
}
As by request, an example. Create a new winform project to test it out.
As default you get a Form1. Add a button to it, double click on it so you get a autogenerated method to it.
Replace the class Form1 with this.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
GuiCursor.WaitCursor(() => { DoSomething(); });
}
private void DoSomething()
{
Thread.Sleep(3000);
}
}
internal class GuiCursor
{
private static GuiCursor instance = new GuiCursor();
private GuiCursor() { }
static GuiCursor() { }
internal static void WaitCursor(MethodInvoker oper)
{
if (Form.ActiveForm != null && !Thread.CurrentThread.IsBackground)
{
Form myform = Form.ActiveForm;
myform.Cursor = Cursors.WaitCursor;
try
{
oper();
}
finally
{
myform.Cursor = Cursors.Default;
}
}
else
{
oper();
}
}
internal static void ToggleWaitCursor(Form form, bool wait)
{
if (form != null)
{
if (form.InvokeRequired)
{
form.Invoke(new MethodInvoker(() => { form.Cursor = wait ? Cursors.WaitCursor : Cursors.Default; }));
}
else
{
form.Cursor = wait ? Cursors.WaitCursor : Cursors.Default;
}
}
}
internal static void Run(Form form)
{
try
{
Application.Run(form);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
}
A little trick to do this could be to use a PictureBox with image in it. On button click, make the PictureBox visible and hide it again after click operation is completed.
This question already has answers here:
How do I update the GUI from another thread?
(47 answers)
Closed 9 years ago.
I have looked for a solution for my problem, but I couldn't find it yet.
I'm coding a bot which will be connected to an irc server. I want the user to have access to a win forms window where it is possible to input the server, channel, and so on.
This is the window:
I have set the console output to update my textbox with the code in the main program. With this, I get all text coming from the child classes into my text box.
static class Program
{
private static Form1 Form1;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
using (var consoleWriter = new ConsoleWriter())
{
consoleWriter.WriteLineEvent += consoleWriter_WriteLineEvent;
Console.SetOut(consoleWriter);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form1 = new Form1();
Application.Run(Form1);
}
}
static void consoleWriter_WriteLineEvent(object sender, ConsoleWriterEventArgs msg)
{
var message = msg.Value;
Form1.statusTextBox.AppendText(message + "\r\n");
}
}
public class ConsoleWriter : TextWriter
{
public override Encoding Encoding { get { return Encoding.UTF8; } }
public override void Write(string value)
{
if (WriteEvent != null) WriteEvent(this, new ConsoleWriterEventArgs(value));
base.Write(value);
}
public override void WriteLine(string value)
{
if (WriteLineEvent != null) WriteLineEvent(this, new ConsoleWriterEventArgs(value));
base.WriteLine(value);
}
public event EventHandler<ConsoleWriterEventArgs> WriteEvent;
public event EventHandler<ConsoleWriterEventArgs> WriteLineEvent;
}
public class ConsoleWriterEventArgs : EventArgs
{
public string Value { get; private set; }
public ConsoleWriterEventArgs(string value)
{
Value = value;
}
}
Now I call this in my Form1, when the button "Connect" is clicked on:
gbaIrcBot.Connect(server, null, port, nick, channelList);
Inside the gbaIrcBot.Connect(), i have among other things:
private void ReadStream()
{
string inputLine;
while ((inputLine = _streamReader.ReadLine()) != null)
{
var splitInput = inputLine.Split(new[] { ' ' });
if (splitInput.ElementAt(0) == "PING") { Pong(splitInput.ElementAt(1)); continue;}
switch (splitInput.ElementAt(1))
{
case "001": foreach (var channel in ChannelList) JoinChannel(channel); break;
case "PRIVMSG": ProcessPrivMsg(splitInput); break;
case "433": SetNick("AlternativeBOT"); break;
default: Console.WriteLine(inputLine); break;
}
}
}
This method is responsible for reading all inputs from the irc server. When I get messages from the server, I send it to the console, which updates the textbox in Form1. It MUST be an infinite loop.
All this works well if I dont create a thread to keep my UI not frozen. This is an example:
When I try to create a thread, My Form1 throws an exception saying its a cross-thread message, and I cannot update it from outside.
Any idea to solve it?
WinForms UI updates have to be performed on the UI thread. Try this approach:
How to update the GUI from another thread in C#?
The update on the form must be done in the window update thread.
You can force the execution in such thread by wrapping your call with BeginInvoke().
Change
Form1.statusTextBox.AppendText(message + "\r\n");
to
Form1.BeginInvoke(() => Form1.statusTextBox.AppendText(message + "\r\n"));
How to avoid multiple instances of windows form in c# ?? i want only one instance of the form running. Because there are chances of opening the same form from many pages of my application.
implement the Singleton pattern
an example: CodeProject: Simple Singleton Forms (ok, it's in VB.NET, but just to give you a clue)
Yes, it has singleton pattern,
Code to create a singleton object,
public partial class Form2 : Form
{
.....
private static Form2 inst;
public static Form2 GetForm
{
get
{
if (inst == null || inst.IsDisposed)
inst = new Form2();
return inst;
}
}
....
}
Invoke/Show this form,
Form2.GetForm.Show();
When you display the dialog simply use .ShowDialog(); instead of .Show();
One solution I applied to my project in order to bring this form again in the foreground is:
private bool checkWindowOpen(string windowName)
{
for (int i = 0; i < Application.OpenForms.Count; i++)
{
if (Application.OpenForms[i].Name.Equals(windowName))
{
Application.OpenForms[i].BringToFront();
return false;
}
}
return true;
}
windowName is essentially the class name of your Windows Form and
return value can be used for not creating a new form instance.
If your system has the possibility of showing the same type of form for different instance data then you could create a checking system that iterates all existing open forms, looking for a unique instance data identifier and then re-display any found form.
e.g. having a form class 'CustomerDetails' which contains a public property 'CustomerUniqueID':
foreach(Form f in CurrentlyDisplayedForms)
{
CustomerDetails details = f as CustomerDetails;
if((details != null) && (details.CustomerUniqueUD == myCustomerID))
{
details.BringToFront();
}
else
{
CustomerDetails newDetail = new CustomerDetails(myCustomerID);
}
}
We also use the same mechanism to automatically force refreshes of data binding where a customer's data has been edited and saved.
Here is my solution in ShowForm() :
private void ShowForm(Type typeofForm, string sCaption)
{
Form fOpen = GetOpenForm(typeofForm);
Form fNew = fOpen;
if (fNew == null)
fNew = (Form)CreateNewInstanceOfType(typeofForm);
else
if (fNew.IsDisposed)
fNew = (Form)CreateNewInstanceOfType(typeofForm);
if (fOpen == null)
{
fNew.Text = sCaption;
fNew.ControlBox = true;
fNew.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
fNew.MaximizeBox = false;
fNew.MinimizeBox = false;
// for MdiParent
//if (f1.MdiParent == null)
// f1.MdiParent = CProject.mFMain;
fNew.StartPosition = FormStartPosition.Manual;
fNew.Left = 0;
fNew.Top = 0;
ShowMsg("Ready");
}
fNew.Show();
fNew.Focus();
}
private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
{
ShowForm(typeof(FAboutBox), "About");
}
private Form GetOpenForm(Type typeofForm)
{
FormCollection fc = Application.OpenForms;
foreach (Form f1 in fc)
if (f1.GetType() == typeofForm)
return f1;
return null;
}
private object CreateNewInstanceOfType(Type typeofAny)
{
return Activator.CreateInstance(typeofAny);
}
public void ShowMsg(string sMsg)
{
lblStatus.Text = sMsg;
if (lblStatus.ForeColor != SystemColors.ControlText)
lblStatus.ForeColor = SystemColors.ControlText;
}
check this link :
using System;
public sealed class Singleton
{
private static volatile Singleton instance;
private static object syncRoot = new Object();
private Singleton() {}
public static Singleton Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
instance = new Singleton();
}
}
return instance;
}
}
}
Try this code
Public class MyClass
{
//Create a variable named
public static int count = 0;
//Then increment count variable in constructor
MyClass()
{
count++;
}
}
While creating the object for the above class 'MyClass' check the count value greater than 1
class AnotherClass
{
public void Event()
{
if(ClassName.Count <= 1)
{
ClassName classname=new ClassName();
}
}
}
Here's a simple way to do it.
Check if the form is null, or has been disposed. If that's true we create a new instance of the form.
Otherwise we just show the already running form.
Form form;
private void btnDesktop_Click(object sender, EventArgs e)
{
if (form == null || desktop.IsDisposed)
{
form = new Form();
form.Show();
}
else
{
form.WindowState = FormWindowState.Normal;
}
}
private static MyForm _myForm;
internal static MyForm form
{
get
{
if (_myForm == null)
{
_myForm = new MyForm();
}
return _myForm;
}
}
public MyForm()
{
InitializeComponent();
_myForm = this;
}
private void MyForm_FormClosed(object sender, FormClosedEventArgs e)
{
_myForm = null;
}
Singletons are not object-oriented. They are simply the object version of global variables. What you can do is to make the constructor of the Form class private, so nobody can accidentally create one of these. Then call in reflection, convert the ctor to public and make sure you create one and only one instance of it.
You can check the existing processes prior to opening the form:
using System.Diagnostics;
bool ApplicationAlreadyStarted()
{
return Process.GetProcessesByName(Process.GetCurrentProcess.ProcessName).Length == 0;
}
I don't know if the GetProcessesByName method is affected by UAC or other security measures.