i'm building a win App and in that, i'm having a textBox which is get filled dynamically, and i have a checkBox, when checkBox.Checked=true all the message boxes in my app will get pop'd
(not all at a time, just confirmation msg's whereever i hv coded it, one by one).
my problem is when checkBox is checked, my TextBox.Text is getting filled its data but when that checkBox is unchecked, TextBox.text is not getting filled with data, wierd thing is when i tried to debug it, TextBox.Text is showing the text, but on gui TextBox.Text is not filled, now where`s data ?
public void Recharge()
{
txtTransactionMsgDelegate(Tm) // this is delegate function which fills the text
//textbox.text=tm; i tried this one too,but no use
}
if (Program.AutoManual == "Auto")
{
if (chkShowMsg.Checked)
{
if (returnRows < 1)
MessageBox.Show(Program.StatusMessage + " But Local Db Failed, NOTEDOWN IN NOTEBOOK");
else
MessageBox.Show(Program.StatusMessage + " And Local Db update SuccessFul, RUN UPDATE RECHARGE LATER");
}
}
Delegate Function:
// m using this delegate b'coz my above function i.e Recharge() is under BackGroundWorker Thread i.e BackGroundWorker_DoWork() event;
private void txtTransactionMsgDelegate(string Text)
{
if (txtTransactionMsg.InvokeRequired)
{
txtTransactionMsg.Invoke(new Action(delegate() { txtTransactionMsgDelegate(Text); }));
}
else
txtTransactionMsg.Text = Text;
}
To make sure the textbox is updated on the GUI you should call txtTransactionMsg.Refresh();
Related
I have to work on a C# GUI application that displays information regarding an alternator that sends back messages every 20ms. So whenever I receive a certain message for ex regarding the temperature, I have to update a Textbox's text property on the UI with the correct information. The problem is I have tried using multithreading with delegates, did not work, and using invoke's did not work. Using a thread pool didn't work. I just want a chunk of code that forces the UI to update a textbox's text property and never thought this could be that hard.
At the moment I have this:
delegate void UpdateTextBoxTextDelegate(double newValue);
private void UpdateTextBoxText(double newValue)
{
if(tbxTemp.InvokeRequired)
{
UpdateTextBoxTextDelegate del = new UpdateTextBoxTextDelegate(UpdateTextBoxText);
tbxTemp.Invoke(del, new object[] {newValue});
}
else
{
tbxTemp.Text = Convert.ToString(newValue + "°C");
}
}
private double alternatorTemperature;
public double _alternatorTemperature
{
get { return alternatorTemperature; }
set
{
alternatorTemperature = value;
UpdateTextBoxText(alternatorTemperature);
}
}
And then I have this function which is basically executing every time a CAN message is received with a certain PGN. This function call hierarchy basically leads back up to the main thread of the application, not the UI thread if that helps.
//Alternator Temperature
case 0xFEA7:
temp = (UInt16)(canMessage.Data4);
alternatorTemperature = Convert.ToDouble(temp);
_alternatorTemperature = alternatorTemperature;
break;
The following code changes the textbox text almost 20 seconds later after there have been thousands of messages sent which is not acceptable. I have also tried the invoke way but only has the same delayed result
tbxRPM.Invoke(new Action(() => tbxRPM.Text = alternatorRPM.ToString() + "/rpm"));
If anyone has an easy way of changing a textbox.text property and then have it immediately show up on the UI, it would be great.
I would recomend you to create a class representing your "Alternator" with a property for "Temperature" and one method for "GetTemperature" that would be the same has your "function which is basically executing every time a CAN message is received with a certain PGN". Once it is done, bind your textbox to the instatiated class and property using:
tbxTemp.DataBindings.Add("Text",
objAlternator,
"Temperature",
false,
DataSourceUpdateMode.OnPropertyChanged);
In the end, the method I used to force UI controls to change even though the main thread was busy all the time was the following. I used this method on text boxes and it turned out to be very responsive
private string _someVariable = "Initial text";
public string SomeVariable
{
get { return _someVariable; }
set { _someVariable= value;
if(PropertyChanged != null)
{
PropertyChanged(this,new System.ComponentModel.PropertyChangedEventArgs(SomeVariable));
}
}
}
Within the main form's constructor I added the following:
lblTextBox.DataBindings.Add("Text", this, "SomeVariable");
And then to trigger changes on the UI controls when I needed I just changed the text property of the textbox you bound the data to and it just worked without the need for multi-threading, delegates, or any complex stuff.
eg.
Where you need a control to change:
lblTextBox.Text = "Some text";
I am currently developing a business program now when the program is launched it checks to see if the set-up has been completed through a non visible checkbox (I.E. If the user has done the set-up the check box will be checked if not it will be not checked)
I have tried googling this with no clear answer to how to do this.
So my question is, can I set the default text of a text box AND the default state of a checkbox through another form.
I.E. The user runs through the set-up and types the license key which then transfers to the main menu form where the program checks the license key. THEN when they finish the set-up it then checks a checkbox on the main menu so the set-up no longer shows up.
I already know how to transfer the text from form2 to form1 but I am just stuck on how to get it to set the default text to the text from form2.
This is the code from Form1:
private void setup()
{
if(checkBox1.Checked == false)
{
MessageBox.Show("ERROR: No setup recorded. Entering Setup Now!");
timer1.Enabled = false;
Setup1 ds = new Setup1();
ds.ShowDialog();
textBox1.Text = ds.textBox1.Text;
}
if(checkBox1.Checked == true)
{
}
Form1:
http://prntscr.com/r87r4k
Set-Up Form(Form2):
http://prntscr.com/r87r9s
(Ignore the text boxes that state "Inactive" and "Active" that is for changing the license key status in the MYSQL Database.)
So in the end I want it so that the license key textbox (the empty text box in the first screenshot) will always open with the provided license key during setup.
Thank You,
Kadin
Yes you can. Just override the default constructor for the form class and you will be set.
public MyForm(string text = “default text”)
{
InitializeComponent();
textBox1.Text = text;
}
EDIT: Create a new constructor and pass an optional parameter. If you dont’t set the value of 'text' then “default value” is going to be set.
Add a public method on your Setup1 called SetText(string text);
public void SetText(string text, bool isCompleted)
{
TextBox1.Text = text;
CheckBox1.Checked = isCompleted;
}
Then when you create your Setup1
Setup1 ds = new Setup1();'
// Set the text you want.
ds.SetText(myText, true);
I've spent 4 hours on this and totally failed.
I know that i need to use BackgroundWorker but all the tutorials refer to running a progress script on the actual form you are running the worker on.
I have a large datagrid, which the user can use a check box to "select all" and then press "UPDATE ALL"
This updates every grid with a bunch of options they choose.
For some users this may be 5 records which is nothing, but some might update 200 records with 5 options which takes about... 10-15 secs to iterate through them.
I have tried so many variations of running BGworker which loads a FrmLoading.Showdialog
Or trying to have BGworker "do work" running the code and then the main thread having the FrmLoading.Show()
However nothing is working.
If i have the update code in the background worker, it fails because the datagrid and everything is in a different thread.
The other way round, and it just hangs on FrmLoading.Show()
Any advice would be great.
I just can't seem to get my head around how to get this working for what seems to be an easy idea!
Current Update Code:
foreach (DataGridViewRow rowx in dataGridpatients.Rows)
{
//MessageBox.Show(Convert.ToBoolean(rowx.Cells["clnselected"].Value).ToString());
if (Convert.ToBoolean(rowx.Cells["clnselected"].Value) == true)
{
//if cycle has a value.
if (cmbcycle.SelectedIndex != -1)
{
rowx.Cells["clncycletype"].Value = cycle;
rowx.Cells["clnpackscollect"].Value = packs;
}
//if location has a value
if (cmblocation.SelectedIndex != -1)
{
location = Convert.ToInt32(cmblocation.SelectedValue);
rowx.Cells["clnlocation1"].Value = location;
}
if (cmbsize.SelectedIndex != -1)
{
size = Convert.ToInt32(cmbsize.SelectedValue);
rowx.Cells["clnpacksize"].Value = size;
}
if (chkDelivery.Checked == true)
{
rowx.Cells["clnDelivery"].Value = true;
}
if (chkSignSheet.Checked == true)
{
rowx.Cells["clnSigningSheet"].Value = true;
}
}
countupdated++;
}
foreach (DataGridViewRow row in dataGridpatients.Rows)
{
row.Cells["clnselected"].Value = false;
row.DefaultCellStyle.BackColor = Color.White;
}
cmbsize.SelectedIndex = -1;
cmblocation.SelectedIndex = -1;
cmbcycle.SelectedIndex = -1;
chkDelivery.Checked = false;
chkSignSheet.Checked = false;
#countupdated++;
I also have #CountSelected.
What i want to do is run this code above but have a popup overlay (dialog) with my logo + "Updating X%"
Where X = countupdated/countselected * 100
I now know i need to use the background worker and invoke for the above, but literally have no idea regarding how to invoke the grid and go from there.
I understand i need to invoke the variables I'm using
(eg. cmbcycle.SelectedIndex)
I know iterating through 150 records and updating individual cells is probably wrong,
My other option is creating a datatable from "selected" cells on that datatable
then Running the update via SQL instead of iterating through a bound table.
Then after the SQL i can re-create the table which will now have the new cell values updated in it?
Would that be a more appropriate way to do it?
Max rows on this table would be 200. Average ~70 so we are never talking 500 or 1000
EDIT:
So the checked answer works to run the background worker and refer to the controls on the form.
The issue is that if i do this:
backgroundWorker1.RunWorkerAsync();
splashy.ShowDialog();
Then the splash screen pops up after the background worker ends
If i do this:
splashy.ShowDialog();
backgroundWorker1.RunWorkerAsync();
Then the popup semi-forms and hangs until the end of the background worker, at which time it closes
because of the RunWorkerCompleted event.
EDIT:
I have no updated the code in DoWork and used Invokes to refer to the controls.
This works and the code runs fine.
I now need a popup ot appear showing the progress through the updates.
splashy.InvokeBy(() =>
{
splashy.Show();
});
backgroundWorker1.RunWorkerAsync();
Does not work. It causes the popup but freeze
splashy.ShowDialog();
backgroundWorker1.RunWorkerAsync();
Allows the Dialog to show (not 'frozen' and distorted) However the Lab (lblprogress) does not update.
This is because the form never get to the RunWorker method, it is stuck at ShowDialog.
It would be a good idea to make modifications on your DataSource itself and then bind it with the DataGridView.
But as from your existing code if you want to access your controls/UI to update or change values from BackgroundWorker.RunWorkerAsync method or any other Thread call for that matter, you can create an extension method to .Invoke() the controls like:
public static class MyExtensions
{
public static void InvokeBy(this Control ctl, MethodInvoker method)
{
if (ctl.InvokeRequired)
ctl.Invoke(method);
else method();
}
}
Keep this static class under the same Namespace as your main class for convenience.
Thus this code:
foreach (DataGridViewRow rowx in dataGridpatients.Rows)
{
//your codes
}
Will become:
dataGridpatients.InvokeBy(() =>
{
foreach (DataGridViewRow rowx in dataGridpatients.Rows)
{
//your codes
}
});
Similarly,
if (cmbcycle.SelectedIndex != -1)
{
//your codes
}
Will become:
cmbcycle.InvokeBy(() =>
{
if (cmbcycle.SelectedIndex != -1)
{
//your codes
}
});
This way you van safely access your controls, while keeping your UI responsive at the same time. Update your Popup Status UI the same way!
This answer is based around o_O's answer.
The main issue is that i wanted the UI to actually update and the background worker to supply the splash.
Instead of running all the 'hard code' in the BGW, i left it in the original thread, but called a BGW to display a popup Dialog form.
so at the start of the "hard code" I used:
backgroundWorker1.RunWorkerAsync();
This called:
FrmSplash splashy;
private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
splashy = new FrmSplash();
splashy.ShowDialog();
}
In order to remove the dialog box, at the end of the code in the GUI thread, i used:
splashy.InvokeBy(() =>
{
splashy.Close();
}
);
backgroundWorker1.CancelAsync();
Which uses the extension supplied by O_o
public static class MyExtensions
{
public static void InvokeBy(this Control ctl, MethodInvoker method)
{
if (ctl.InvokeRequired)
ctl.Invoke(method);
else method();
}
}
I have also built a label update into splashy
So i could call
splashy.InvokeBy(() =>
{
splashy.SetStatus(countupdated.ToString());
}
);
As i iterated through the datagridview rows. This updated the label on the splash screen :)
Im currently facing the problem that when i try to set focus on some control (textBox), nothing happens, maybe i just overlooked something.(somewhere i found that focus is "low-level" method and that select() should be used instead, however, it doesnt work as well)
From form Login, i launch new instance of EncryptPSW form
private void openToolStripMenuItem_Click(object sender, EventArgs e)
{
EncryptPSW ePSW = new EncryptPSW();
ePSW.setOsLog(false, this);
ePSW.ShowDialog();
}
On Button(which is located on EncryptPSW form ) click event i call fill method
public void fill()
{
if (textBoxPSW.Text.Length == 8)//psw has to be 8 chars long
{
if (save)//determinating whether save or fetch of data should be done
{ login.launchSave(textBoxPSW.Text,this); }
else { login.launchOpen(textBoxPSW.Text,this); }
}
else { MessageBox.Show("The password must contain 8 characters");}
}
Which launches either save or open method from Login (my problem is just with open, since during save i dont need to do anything with Focus)
public void launchOpen(string psw,EncryptPSW ePSW)
{
ePSW.Close();
Encryptor.DecryptFile("loggin.bin", psw, this); //decrypting data and setting textBoxes Text property into the fetched ones
setFocus();
}
After all the work is done, setFocus() should be called in order to set focus and other properties.
public void setFocus()
{
textBoxDatabase.Focus();
textBoxDatabase.SelectionStart = textBoxDatabase.TextLength - 1;
textBoxDatabase.SelectionLength = 0;
}
I tried so many different ways, like:
Calling setFocus() from within EncryptPSW_FormClosed
Calling whole open process after the EncryptPSW is closed (from within EncryptPSW_FormClosed)
and many more, however i dont remember it all.
In the case of Form_Closed the weird thing is, that when i tried to show a message box from there instead of setting focus (just to see where the problem might be), it's showed before the EncryptPSW form is closed.
My only guess about this is that the instance of EncryptPSW is somehow blocking Login form and it's controls
I hoped i described my problem well enough and that it makes at least a bit of sense ;]
Thanks in advance,
Regards,
Releis
Since the textbox is in the login form, and you are opening the EcryptPWS from it as a dialog (child), your login form will not be able to set focus to anything. You will need to set focus after it is closed. You can do this:
private void openToolStripMenuItem_Click(object sender, EventArgs e)
{
using(EncryptPSW ePSW = new EncryptPSW())
{
ePSW.setOsLog(false, this);
if (ePSW.ShowDialog() == DialogResult.OK)
{
textBoxDatabase.Focus();
}
}
}
public void launchOpen(string psw,EncryptPSW ePSW)
{
ePSW.DialogResult = DialogResult.OK;
ePSW.Close();
Encryptor.DecryptFile("loggin.bin", psw, this); //decrypting data and setting textBoxes Text property into the fetched ones
}
OK this maybe the ugliest thing I saw round this but.
using
public void setFocus()
{
textBoxDatabase.Focus();
textBoxDatabase.SelectionStart = textBoxDatabase.TextLength - 1;
textBoxDatabase.SelectionLength = 0;
}
Change your code at
public void launchOpen(string psw,EncryptPSW ePSW)
{
ePSW.Close();
Encryptor.DecryptFile("loggin.bin", psw, this); //decrypting data and setting textBoxes Text property into the fetched ones
setFocus();
}
to
delegate void settingfocus();
public void launchOpen(string psw,EncryptPSW ePSW)
{
ePSW.Close();
Encryptor.DecryptFile("loggin.bin", psw, this); //decrypting data and setting textBoxes Text property into the fetched ones
settingfocus sf = new settingfocus(setFocus);
this.BeginInvoke(sf);
}
This worked for me
(Sorry for apparently thinking insert "this" before procedure, and change line x to this was legable)
Not sure if i will be able to formulate my question quite clear but let me try:
So i've written a small piece of code which will give the user the option to select a desired status for his Office Communicator when his PC get locked ( by default it goes automatically on status "away" ) .So here it is the Windows Form wich is basically a combobox and a button .The Combo has four option "Away" , "Busy" , Do not Disturb" and "Online" respectively. All seems fine and the program compiles ok.The Menu appears , you select the status you wish , push the button and then lock your PC - so far all goes perfect.Your Status is as selected .And now comes the Problem.You unlock your PC and try to select a different status , same actions , but when you lock the PC it still shows the previously selected status here is the Button_Click method
public void Btn_Click(Object sender, EventArgs e)
{
// When the button is clicked,
// change the button text, and disable it.
if (Comb.Text == "Away")
{
MessageBox.Show("Saved ! \nYour Status will be 'Away' ");
Method2();
}
else if (Comb.Text == "Busy")
{
MessageBox.Show("Saved ! \nYour Status will be 'Busy' ");
Method1();
}
else if (Comb.Text == "Do Not Disturb")
{
MessageBox.Show("Saved ! \nYour Status will be 'Do Not Disturb' ");
Method3();
}
else
{
MessageBox.Show("Saved ! \nYour Status will be 'Online' ");
Method4();
}
But.Enabled = true;
// Display the greeting label text.
}
So the 4 methods ( Method1 () , 2 ... etc ) are the one to change the status depending on the text in the combo box drop down menu ( the status you select )i have tested all methods separately from each other and they work beautiful thereforfe i exclude a problems with them , is it some logical error ?
Nikolay, give SharpDevelop's debugger a try. In your code's margin click once next to the line if (Comb.Text == "Away") and then hover over the variable names to see what they are set to each time it runs. You can use the "Step over" "Step into" and "Step out" functions to "Execute the highlighted method without looking at the internals", "Debug the Internals of a method" or "Run the current method to the end and then show the next level up" respectively.
If you do this you'll figure out why you're getting an error and it will be MUCH easier to determine where the error is coming from. (For instance, if a variable is set to an unexpected value you'll know to figure out when that changed).
static void SystemEvents_SessionSwitch1(object sender, SessionSwitchEventArgs e)
{
if (e.Reason == SessionSwitchReason.SessionLock)
{
System.Threading.Thread.Sleep(500);
CommunicatorAPI.MessengerClass comm = new CommunicatorAPI.MessengerClass();
if (comm.MyStatus==MISTATUS.MISTATUS_AWAY)
{
SetMyPresence1 ();
} else if (e.Reason == SessionSwitchReason.SessionUnlock)
{
ChangeStatus1 ();
}
}
}