System.Threading.ThreadStateException: how to solve it? - c#

I have a Windows forms Application to open the file dialog, and then view xml files and xlsx files in a datagridview. I wrote the following code, Is my code OK or I need to do something more?
namespace MyFirstWindos
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Button1_Click(object sender, EventArgs e)
{
openFD.InitialDirectory = "C:";
openFD.Title = "Insert an File";
openFD.FileName = "";
openFD.Filter = "XML Files |*.xml| XLSX Files |*.xlsx ";
if (openFD.ShowDialog() == DialogResult.OK)
{
DataSet ds = new DataSet();
ds.ReadXml(openFD.FileName);
dataGridView1.DataSource = ds.Tables[0];
}
else
{
MessageBox.Show("Operation Cancelled");
}
}
}
}
namespace MyFirstWindos
{
public static class Program
{
public static void Main()
{
Compare_D_A d_A = new Compare_D_A();
d_A.CompareD_A();
// Compare_D_R d_R = new Compare_D_R();
// d_R.compareD_R();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
I have this exception
"System.Threading.ThreadStateException: 'The current thread must be set to single thread containment (STA) mode before OLE calls can be made. Make sure that the Main function is marked with STAThreadAttribute.
This exception is only activated if a troubleshooting program is linked to the process, at this row in my code if (openFD.ShowDialog() == DialogResult.OK).
How I can correct it and what it means?

Related

C# DataGridView - Table is not populating

I'm trying to display data that I pull from text files within my program.cs to a DataGridView, but the table remains blank when I run the code.
Another problem I have is that when the form opens it stops running through the code.
Basically what the code does is it downloads .zip files from an sftp server, unzips a text file, reads through the file adding each line to an array and splits a certain line into an array. I'm trying to get the variables from that array to appear on a DataGridView in my form.
Here is my code:
class Machine
{
public string MacNum { get; set; }
public string CashCount { get; set; }
public string VendCount { get; set; }
}
static class Program
{
[STAThread]
static void Main()
{
string zipTemp = (#"C:\Users\mark\Desktop\Project Dex\zipTemp\");
string machineCashCount = ("");
string hostIP = ("0.0.0.0");
string userName = ("UN");
string passWord = ("PW");
string remotePath = (#"/home/dex/RESPONSE/PROCESSED");
string localPath = (#"C:\Users\mark\Desktop\Project Dex\Temp\PROCESSED\");
Application.Run(new Form1());
DataGridView dataGridView = new DataGridView();
IList<Machine> machines = new BindingList<Machine>();
dataGridView.DataSource = machines;
SessionOptions sessionOptions = new SessionOptions
{
Protocol = Protocol.Sftp,
HostName = hostIP,
UserName = userName,
Password = passWord,
PortNumber = 22,
SshHostKeyFingerprint = "ssh-rsa 2048 96:48:96:52:8c:e7:de:c6:e1:00:08:7e:db:ad:e4:06"
};
using (Session session = new Session())
{
session.Open(sessionOptions);
TransferOptions transferOptions = new TransferOptions();
transferOptions.TransferMode = TransferMode.Binary;
session.GetFiles(remotePath, #"C:\Users\mark\Desktop\Project Dex\Temp\").Check();
}
DirectoryInfo directorySelected = new DirectoryInfo(#"C:\Users\mark\Desktop\Project Dex\Temp\PROCESSED\");
List<string> fileNames = new List<string>();
foreach (FileInfo fileInfo in directorySelected.GetFiles("*.zip"))
{
fileNames.Add(fileInfo.Name);
}
foreach (string fileName in fileNames)
{
string zipFilePath = localPath + fileName;
using (ZipFile zip1 = ZipFile.Read(zipFilePath))
{
var selection = (from e in zip1.Entries
where (e.FileName).StartsWith("01e")
select e);
Directory.CreateDirectory(zipTemp);
foreach (var e in selection)
{
e.Extract(zipTemp, ExtractExistingFileAction.OverwriteSilently);
}
}
DirectoryInfo dexDirect = new DirectoryInfo(#"C:\Users\mark\Desktop\Project Dex\zipTemp\");
List<string> dexName = new List<string>();
foreach (FileInfo dexInfo in dexDirect.GetFiles("*.dex"))
{
dexName.Add(dexInfo.Name);
}
foreach (string dexNames in dexName)
{
string dexFilePath = zipTemp + dexNames;
string[] lines = System.IO.File.ReadAllLines(dexFilePath);
foreach (string line in lines)
{
machineCashCount = Array.Find(lines,
element => element.StartsWith("VA1", StringComparison.Ordinal));
}
string[] MCC1 = machineCashCount.Split('*');
string[] nm = dexNames.Split('.');
int nam = int.Parse(nm[0], System.Globalization.NumberStyles.HexNumber);
// Console.WriteLine((nam + (":") + "Total cash count: ") + MCC1[1]);
// Console.WriteLine((nam + (":") + "Number of paid vends: ") + MCC1[2]);
Machine m = new Machine();
m.MacNum = nm[0];
m.CashCount = MCC1[1];
m.VendCount = MCC1[2];
machines.Add(m);
}
}
Application.Run(new Form1());
}
}
Form1:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public void Form1_Load(object sender, EventArgs e)
{
}
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
}
}
1.Delete
Application.Run(new Form1());
DataGridView dataGridView = new DataGridView();
and
dataGridView.DataSource = machines;
2.At the end change
Application.Run(new Form1());
to
Application.Run(new Form1(machines));
3.Add constructor to Form1:
public Form1(IList<Machine> machines)
{
InitializeComponent();
dataGridView1.DataSource = machines;
}
What your program is basically doing is it runs the Form, downloads the zip file, processes the zip file and that's it.
You will need to do all this in the form's form_load event or a button click event instead of the Main().
remove the Application.Run(new form1) from the beginning of the code. Not required.
Move everything before the last Application.Run(new Form1) [Note this is with 'F' which is the correct one] to the a private function inside the form. Let's call it processFile()
Call this processFile() in the Form1_Load() event.
Assign m to the DataGridView's data property and call DataGridView.Bind() to bind the data to the datagrid control.
UPDATE:
Since you have a button and a Button_Click event, put the processFile() in the Button's click event. When the form is displayed, click the button to get the whole process running

Getting exception while pressing a button in c#

I have made a button using c# to browse files and folders from windows. My sample code is given below. The problem is: when I click on the browse button I am getting the following exception in the line I have marked in the comment in the following code:
An unhandled exception of type 'System.Threading.ThreadStateException' occurred in System.Windows.Forms.dll
My sample code:
using System;
using System.Drawing;
using System.Windows.Forms;
using System.IO;
public class Form1 : Form
{
public Form1()
{
Size = new Size(400, 380);
Button browse = new Button();
browse.Parent = this;
browse.Text = "Browse";
browse.Location = new Point(220, 52);
browse.Size = new Size(6 * Font.Height, 2 * Font.Height);
browse.Click += new EventHandler(ButtonbrowseOnClick);
}
public void ButtonbrowseOnClick(object sender, EventArgs e)
{
int size = -1;
OpenFileDialog openFileDialog1 = new OpenFileDialog();
DialogResult result = openFileDialog1.ShowDialog(); //getting exception in this line
if (result == DialogResult.OK)
{
string file = openFileDialog1.FileName;
try
{
string text = File.ReadAllText(file);
size = text.Length;
}
catch (IOException)
{
}
}
Console.WriteLine(size);
Console.WriteLine(result);
}
public static void Main()
{
Application.Run(new Form1());
}
}
Is there anything wrong in the code?
Using [STAThread] attribute at top of your Main method, should solves the problem.
[STAThread] // <--------Add this
public static void Main()
{
Application.Run(new Form1());
}

Delegate loads the Alert Form but I can't use any of the components.. its stuck

The problem is below. Here's my code...
// Contents of Form1.cs
// Usual includes
namespace ProcessMonitor
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public Boolean getStatus()
{
// Returns true if the system is active
if (label1.Text.Equals("Active"))
return true;
return false;
}
private void button1_Click(object sender, EventArgs e)
{
if(getStatus())
{
label1.Text = "Not Active";
button1.Text = "Activate";
}
else
{
label1.Text = "Active";
button1.Text = "Deactivate";
}
}
private void Form1_Load(object sender, EventArgs e)
{
Monitor mon = new Monitor(this);
mon.Run();
}
}
}
// Contents of Monitor.cs
// Usual includes
using System.Management;
using System.Diagnostics;
using System.Threading;
namespace ProcessMonitor
{
class Monitor
{
Form1 parent;
private void ShowAlert(Alert al)
{
al.Show();
}
public Monitor(Form1 parent)
{
this.parent = parent;
}
public void InvokeMethod()
{
//This function will be on main thread if called by Control.Invoke/Control.BeginInvoke
Alert frm = new Alert(this.parent);
frm.Show();
}
// This method that will be called when the thread is started
public void Run()
{
var query = new WqlEventQuery("__InstanceCreationEvent", new TimeSpan(0, 0, 0, 0, 1),
"TargetInstance isa \"Win32_Process\");
while (true)
{
using (var watcher = new ManagementEventWatcher(query))
{
ManagementBaseObject mo = watcher.WaitForNextEvent();a
//MessageBox.Show("Created process: " + ((ManagementBaseObject)mo["TargetInstance"])["Name"] + ",Path: " + ((ManagementBaseObject)mo["TargetInstance"])["ExecutablePath"]);
ManagementBaseObject o = (ManagementBaseObject)mo["TargetInstance"];
String str = "";
foreach (PropertyData s in o.Properties)
{
str += s.Name + ":" + s.Value + "\n";
}
this.parent.Invoke(new MethodInvoker(InvokeMethod), null);
}
}
}
}
}
Alert.cs is just a blank form with a label that says “new process has started”. I intend to display the name of the process and location, pid, etc. by passing it to this alert form via the Thread (i.e. class Monitor). I have deliberately made the thread load in form_load so that I can resolve this error first. Adding it as a thread properly after the main form loads fully is a later task. I need to fix this first..
The delegate creates the Alert form but I can’t click on it, its just stuck. Need help to solve this.
Your while loop in Run is blocking the UI thread.
by passing it to this alert form via the Thread
You never actually create a new thread or task here - you just run code which executes in the UI thread, and causes an infinite loop. This will prevent the main form, as well as your Alert form, from ever displaying messages.
You need to push this into a background thread in order for it to work, ie:
private void Form1_Load(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(_ =>
{
Monitor mon = new Monitor(this);
mon.Run();
});
}

Starting a second message loop on a single thread is not a valid operation. Use Form.ShowDialog instead

I have one MDIPrent Form that is my main form. Now I am logging out form Main_Form by clicking LogOut MenuStrip. In my code I have prevented duplicate instance. But I get this error. I have googled so much, tried so many things but error doesn't go away.
Below is code for Program.cs file:
using System.Diagnostics;
static class Program
{
[STAThread]
static void Main()
{
LoggedInUser = string.Empty;
loginSuccess = false;
String thisprocessname = Process.GetCurrentProcess().ProcessName;
if (Process.GetProcesses().Count(p => p.ProcessName == thisprocessname) > 1)
return;
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
MyApplicationContext context = new MyApplicationContext();
Application.Run(context);
}
public class MyApplicationContext : ApplicationContext
{
private Login_Form lgFrm = new Login_Form();
public MyApplicationContext()
{
try
{
lgFrm.ShowDialog();
if (lgFrm.LogonSuccessful)
{
////lgFrm.Close();
lgFrm.Dispose();
FormCollection frm = Application.OpenForms;
try
{
foreach (Form fc in frm)
fc.Close();
}
catch (Exception ex){}
Application.Run(new Main_Form());
}
}
catch (Exception ex){}
}
}
}
Below is the code for Login_Form
public bool LogonSuccessful
{
get
{
return Program.loginSuccess;
}
set
{
Program.loginSuccess = value;
}
}
private void BtnEnter_Click(object sender, EventArgs e)
{
Login_Form lgn = new Login_Form();
Program.loginSuccess = true;
this.Hide();
Program.LoggedInUser = TxtBxUserName.Text;
}
Below is for Main_Form
private void LogOutMenuItem_Click(object sender, EventArgs e)
{
Login_Form lgFrm = new Login_Form();
lgFrm.LogonSuccessful = false;
Program.loggedOut = true;
Program.LoggedInUser = string.Empty;
this.Close();
////FormCollection frm = Application.OpenForms;
////foreach (Form fc in frm)
////{
//// MessageBox.Show(fc.ToString());
////}
Program.MyApplicationContext context = new Program.MyApplicationContext();
Application.Run(context);
}
I have used context, because I want to make Main_Form, the only OpenForm of application. Somewhere I got the idea of using the context.
Your exception is because you call Application.Run(...) inside another Application.Run(...), modify as follow:
//MyApplicationContext constructor
public MyApplicationContext()
{
try
{
lgFrm.ShowDialog();
if (lgFrm.LogonSuccessful)
{
////lgFrm.Close();
lgFrm.Dispose();
FormCollection frm = Application.OpenForms;
try
{
foreach (Form fc in frm)
fc.Close();
}
catch (Exception ex){}
//Application.Run(new Main_Form()); <<<---- Remove this
MainForm = new Main_Form();
}
}
catch (Exception ex){}
//Add the ThreadExit event handler here
ThreadExit += (s,e) => {
if(Program.loggedOut) {
Program.MyApplicationContext ctxt = new Program.MyApplicationContext();
Application.Run(ctxt);
}
};
}
}
//
private void LogOutMenuItem_Click(object sender, EventArgs e)
{
Login_Form lgFrm = new Login_Form();
lgFrm.LogonSuccessful = false;
Program.loggedOut = true;
Program.LoggedInUser = string.Empty;
this.Close(); //I think you want to call Application.Restart() here?
//if so, you don't need the ThreadExit event handler added in the MyApplicationContext() constructor.
}
try this: instead of firing a new application when logging off, just dispose your window and replace MyApplicationContext() in this:
public MyApplicationContext()
{
bool isSuccessful = false;
do
{
try
{
lgFrm = new Login_Form();
lgFrm.ShowDialog();
if (lgFrm.LogonSuccessful)
{
isSuccessful = lgFrm.LogonSuccessful;
////lgFrm.Close();
lgFrm.Dispose();
FormCollection frm = Application.OpenForms;
try
{
foreach (Form fc in frm)
fc.Close();
}
catch (Exception ex){}
Application.Run(new Main_Form());
}
}
catch (Exception ex){}
}while(isSuccessful);
}
i had the same problem
the best way to solve this is Using
Application.Restart();
you should Use it when ever a User Log out , so the main UI close
and the log in dialog appear !!
but with Log in Form U gotta use this
ControlBox = False;
so the User can't bypass it by closing it!!
Simply U can add an Exit Button with code
Application.Exit();
this is how i solved this problem with out any additional Usings or Errors ...

Ctrl F5 exception and ignored on F5

I am getting this unhandled exception error shown: See screen shot.
I am getting this error only when I run with Ctrl+ F5 and not in F5(debug mode). Not sure if this is helpful, my computer is a windows 7- 64bit and running a 32 bit build
According to this discussion: How can I get WinForms to stop silently ignoring unhandled exceptions?, adding Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException) it wll cause Windows to ignore the error.
EDIT:
frmPlant_Load Event
public partial class frmPlant : Form
{
DatabaseConnection _DbConnection = new DatabaseConnection();
string conString = ConfigurationManager.ConnectionStrings["RVESTConnString"].ConnectionString;
SQLQueries _SQlQueries = new SQLQueries();
DataSet ds;
SQLiteDataAdapter da;
static DataTable gdt;
int gSelectedPlant;
string gSelectedPlantName = "";
bool ignoreSelChg = false;
bool DataDirty = false;
public frmPlant()
{
InitializeComponent();
}
public frmPlant(int sSelectedPlant)
{
InitializeComponent();
}
private void frmPlant_Load(object sender, EventArgs e)
{
ds = FillData();
gdt = ds.Tables[0];
bindingSource1.DataSource = gdt;
dataGridView1.DataSource = bindingSource1;
gSelectedPlant = StaticClass.GlobalValue;
dataGridView1.AutoGenerateColumns = true;
dataGridView1.Columns["PlantId"].Visible = false;
dataGridView1.Columns["NSSS_Design"].Width = 70;
}
private DataSet FillData()
{
ignoreSelChg = true;
SQLiteConnection con = new SQLiteConnection(conString);
DataSet dPlant;
try
{
con.Open();
SQLiteCommand cmd = new SQLiteCommand("select * from Plant", con);
da = new SQLiteDataAdapter("select * from Plant", con);
dPlant = new DataSet();
da.Fill(dPlant, "plant");
}
catch (Exception ex)
{
throw ex;
}
finally
{
con.Close();
}
return dPlant;
}
I should also add another concern: When I say continue here in the dialog, it works fine but leaves a background process running. I have to manually go and kill it in the task manager
Question: Suppose I add this line in the Program.cs, will it ignore ANY- even genuine errors which need to be fixed?
More Code:
This dialog pops up on button click on the second screen- Initial Setup screen . The first being a splash screen. Initial setup takes me to the Plant form
Here's the code for the initial setup screen
public partial class frmInitialSetUp : Form
{
public frmInitialSetUp()
{
InitializeComponent();
}
private void btnOK_Click(object sender, EventArgs e)
{
Program.fPlant = new frmPlant();
Program.fPlant.Show();
this.Hide();
}
private void frmInitialSetUp_Load(object sender, EventArgs e)
{
Program.LoadAllForms();
}
}
}
Program.cs
static public void LoadAllForms()
{
try
{
Program.fInitialSetUp = new frmInitialSetUp();
Program.fPlant = new frmPlant();
Program.frm*** = new frm***();
Program.frm*** = new frm***();
Program.frm*** = new frm***();
}
catch (Exception ex)
{
throw ex;
}
}
On button click on the
Enclosed the frmload in a try { } catch(unhandledexception ex) {} and ran it in debug mode
This time the debugger caught it. It was a small problem with datagridview columns

Categories

Resources