C# StripStatusText Update Issue - c#

I am here due to a strange behaviour in Button_Click event. The code is attached.
The issue is the first StripStatus message is never displayed. any ideas as to why?
private void FireBtn_Click(object sender, EventArgs e)
{
// Control local controls for launching attack
AwayTableLayoutPanel.Enabled = false;
AwayCancelBtn.Enabled = false;
FireBtn.Enabled = false;
////////////// Below statusBar message is never displayed but the folowing sound clip is.
GameToolStripStatusLabel.Text = "(Home vs. Away)(Attack Coordinate: (" +
GameModel.alphaCoords(GridLock.Column) + "," + GridLock.Row + "))(Action: Fire)";
////////////////////////////////////////////
if (audio)
{
SoundPlayer fire = new SoundPlayer(Properties.Resources.fire);
fire.PlaySync();
fire.Dispose();
}
// compile attack message
XmlSerializer s;
StringWriter w;
FireGridUnit fireGridUnit = new FireGridUnit();
fireGridUnit.FireGridLocation = GridLock;
s = new XmlSerializer(typeof(FireGridUnit));
w = new StringWriter();
s.Serialize(w, fireGridUnit);
//////////////////////////////////////////////////////////
// send attack message
GameMessage GameMessageAction = new GameMessage();
GameMessageAction.gameAction = GameMessage.GameAction.FireAttack;
GameMessageAction.statusMessage = w.ToString();
s = new XmlSerializer(typeof(GameMessage));
w = new StringWriter();
s.Serialize(w, GameMessageAction);
SendGameMsg(w.ToString());
GameToolStripStatusLabel.Text = "(Home vs. Away)(Attack Coordinate: (" +
GameModel.alphaCoords(GridLock.Column) + "," + GridLock.Row + "))(Action: Awaiting Fire Result)";
}
EDIT: if I put in a messageBox after the StripStatus message the status is updated.

There's a lot of stuff going on after you assigned the Text property. The label will not visually update until the Click event handler is done executing. It's Paint event cannot run until the UI thread goes idle again.
You can force it to paint right away by calling the strip's Update() method:
GameToolStripStatusLabel.Text = "...";
GameToolStrip.Update();

Related

Making statements wait before being executed

i have this code, which has an animation and some other statements (they are like resetting the TextBoxs and other UI Controls).
what is happening is that the animation is starting with the statements at he same time, it looks weird that the users sees that the text in the TextBoxs suddenly disappers, so i want these other statements to wait some time (the animation duration) before being executed.
//this is an Animation that takes me back to the home view
switching = (Storyboard)this.FindResource("view_Copy1");
switching.Begin();
//I want these statments to wait until the animation is finished
st1.Children.Clear();
st2.Children.Clear();
st3.Children.Clear();
st4.Children.Clear();
name.Text = lname.Text = fname.Text = mname.Text = sex.Text =
bplace.Text = bday.Text = idcard.Text = socal.Text = region.Text = location.Text =
telephone.Text = mobile1.Text = mobile2.Text = email1.Text = email2.Text =
ctype.Text = cyear.Text = emergname1.Text = emergrelation1.Text = emergloc1.Text =
emergphone1.Text = emergname2.Text = emergrelation2.Text = emergloc2.Text = emergphone2.Text = "";
region.Items.Clear();
New.IsEnabled = true;
id = "";
bt_del.Visibility = Visibility.Collapsed;
There is a Completed event that you can use and on completion you execute your code.
switching.Begin();
switching.Completed += Storyboard_Completed;
...
private void Storyboard_Completed(object sender, EventArgs e)
{
// Your code to execute after the animation completed.
}

ObjectDisposedException while Showing a Form

I keep getting an ObjectDisposedExpection when I need to get a Form to show.
Do you guys maybe know how to do this? In the foreach by NotitiesForm.Show() I get the error ObjectDisposedExpection. I am programming in Visual Studio Ultimate 2012 C#.
RichTextBox NotitiesTB = new RichTextBox();
private Form NotitiesForm;
/// <summary>
///
/// </summary>
/// <param name="label"></param>
///
public void NotitiesLatenZien()
{
if (filename != null)
{
BRTSignal signal = new BRTSignal(filename);
BRTEventRepository Notities = new BRTEventRepository(signal);
List<IBRTNote> note = Notities.ReadNotes();
BRTEventService TijdNotities = new BRTEventService(signal);
TijdNotities.MakeNoteTimesRelativeToTrack(note, 1);
//TextBox NotitiesTB = new TextBox();
//NotitiesTB.Name = "Notities";
if (NotitiesForm == null)
{
NotitiesForm = new Form();
}
NotitiesForm.Height = 600;
NotitiesForm.Width = 1000;
NotitiesForm.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
NotitiesForm.MaximizeBox = false;
NotitiesForm.Disposed +=NotitiesForm_Disposed;
NotitiesForm.Text = "Notities";
NotitiesTB.Multiline = true;
NotitiesTB.Height = 600;
NotitiesTB.Width = 980;
NotitiesTB.ReadOnly = true;
NotitiesTB.Clear();
//NotitiesTB.Click += NotitiesTB_Click;
//NotitiesTB.SelectionStart = Convert.ToInt32(referenceLineSelectedPage);
NotitiesTB.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.Both;
NotitiesTB.Name = "Notities";
NotitiesForm.Controls.Add(NotitiesTB);
foreach (IBRTNote notes in Notities.ReadNotes())
{
//string test = Convert.ToString((notes.Time));
//textBox1.Text = String.Concat(textBox1.Text, string.Concat(Environment.NewLine, notes.Text));
if (NotitiesTB.Text == "")
{
NotitiesTB.Text += new BRTToDotNET.RTDateTime((long)notes.Time).ToDotNet().ToString() + " " + notes.Text;
}
else
{
NotitiesTB.Text += "\r\n" + new BRTToDotNET.RTDateTime((long)notes.Time).ToDotNet().ToString() + " " + notes.Text;
}
//MessageBox.Show("\r\n" + notes.Text);
NotitiesForm.Show();
NotitiesForm.BringToFront();
}
}
else
{
MessageBox.Show("Er blijkt een .sig file te missen. Controleer of u een .sig file heeft ingeladen.");
}
}
private void NotitiesForm_Disposed(object sender, EventArgs e)
{
NotitiesForm = null;
}
The code you posted seem "good enough". That is, you set the NotitiesForm variable when the object is disposed, and you create a new one if it's null. As long as all this code executes in the main UI thread, that part is fine.
But note that all controls in a Form are disposed of when the Form is disposed. So your NotitiesTB control will be disposed of the first time your NotitiesForm is closed. You then add that control to the next Form instance you create, and when it's shown, you get the exception because you're trying to show a Form containing a control that has already been disposed.
The right way to do this would be to design an actual Form subclass that already contains the RichTextBox instance you want. Then you don't have to keep adding a new instance to each new instance of the Form you create.
Barring that, then you need to create a new RichTextBox instance to go with each new Form instance you create, e.g. in the same place where you have the NotitiesForm = new Form(); statement.

C# Variable won't update

I'm writing a C# Program to display the Temperature of CPU/GPU from my PS3.
There is a connect button. This works really good and it shows me the Temp. from my PS3's CPU/GPU.
Now I've implemented a "refresh" button, which starts a timer for all x Seconds to do this:
public void get_psdata()
{
//Get data from PS3
cputemp = PS3.GetTemperatureCELL();
gputemp = PS3.GetTemperatureRSX();
psversion = PS3.GetFirmwareVersion();
psversiontype = PS3.GetFirmwareType();
//Set data into Var
L_cputemp_show.Text = cputemp;
L_gputemp_show.Text = gputemp;
L_firmware_show.Text = psversion;
L_type_show.Text = psversiontype;
//Update Label
L_cputemp_show.Refresh();
}
So this "get_psdata" works only on the first time, when i press the connect button. (The connect button starts directly the "get_psdate" function, while the refresh button does a bit different, like you can see later...)
Here is the code to run the get_psdata:
//B_connect, Connect Button
private void b_connect_Click(object sender, EventArgs e)
{
//Connect CCAPI to PS3 if Button clicked
PS3.ConnectTarget(psip);
//Check Connection
if (PS3.SUCCESS(PS3.ConnectTarget(psip)))
{
//Show Status
MessageBox.Show("Connected to: " + psip + "!");
this.L_status_show.Text = "Connected!"; L_status_show.ForeColor = System.Drawing.Color.Green;
//Call Function
get_psdata();
}
else
{
//Show Status
MessageBox.Show("Failed to Connect to: " + psip + "!");
this.L_status_show.Text = "Not Connected!"; L_status_show.ForeColor = System.Drawing.Color.Red;
}
}
For testing, I added a Messagebox.Show to the "get_psdata" function to see if it runs all x Seconds... Yes it does and this is my timer:
//Function to set refresh delay
public void refresh_delay()
{
MessageBox.Show("Delay set to " + refresh_int + " Seconds!");
refresh_int = refresh_int * 1000; //Change to Miliseconds
init_timer();
}
//Timer
public Timer timer1;
public void init_timer()
{
timer1 = new Timer();
timer1.Tick += new EventHandler(timer1_Tick);
timer1.Interval = refresh_int; // in miliseconds
timer1.Start();
}
public void timer1_Tick(object sender, EventArgs e)
{
get_psdata();
}
And this is what starts my timer:
//B_set, Set refresh time button
private void B_set_Click(object sender, EventArgs e)
{
//Check refresh Value
refresh_string = TB_refresh.Text;
//Check empty
if (refresh_string != "")
{
//Check minimum
refresh_int = Convert.ToInt32(TB_refresh.Text);
if (refresh_int < 5)
{
DialogResult confirm = MessageBox.Show("This is not the delay you are looking for! \r (I recommend to set it bigger then 5) \r Continue with " + refresh_int + " Seconds?", "Realy dude?", MessageBoxButtons.YesNo);
if (confirm == DialogResult.Yes)
{
//Call Function
refresh_delay();
}
}
else
{
//Call Function
refresh_delay();
}
}
else
{
MessageBox.Show("Please set refresh delay!");
}
}
So I'm sure that the code will run all x Seconds but the label's are only updated when I hit the connect button, but not if I start the counter after connecting with the B_set button.
The Variables from "get_psdata" are not showing the updated value. They just show the result from the first "Get". Why aren't they show the latest result?
If I use your code in a fresh winforms screen, all works well. I did however use the following implementation for get_psdata.
public void get_psdata()
{
var rnd = new Random();
//Set data into Var
L_cputemp_show.Text = rnd.Next().ToString();
L_gputemp_show.Text = rnd.Next().ToString();
L_firmware_show.Text = rnd.Next().ToString();
L_type_show.Text = rnd.Next().ToString();
//Update Label
L_cputemp_show.Refresh();
}
With an interval of 1 second, this gives me new values on screen every second. Could you try this code please?
If this works well, then the problem is with the PS3 object that doesn't refresh its internals perhaps?

Updating textbox while another thread is running WPF

Here is the architecture of my app. I have a Perl script that is called using the method below on click of a button.
ProcessStartInfo psStartInfo = new ProcessStartInfo("perl.exe");
psStartInfo.Arguments = paramStr;
psStartInfo.UseShellExecute = false;
psStartInfo.RedirectStandardOutput = true;
psStartInfo.RedirectStandardError = true;
psStartInfo.CreateNoWindow = false;
ps.StartInfo = psStartInfo;
ps.Start();
string os = ps.StandardOutput.ReadToEnd();
The above code executes successfully. There is a text file which is generated using the Perl script I fired in the above mentioned code. I have to read that file and show everything in that in my WPF textbox. That Perl file is updated after every 5 to 10 secs. I use the below mentioned code to read the file and show it in my textbox.
dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
dispatcherTimer.Interval = new TimeSpan(0, 0, 30);
dispatcherTimer.Start();
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
txtExecLog.Text = "";
if (File.Exists("C:\\FlashAuto\\Execution_Logs\\log.txt"))
{
File.Copy("C:\\FlashAuto\\Execution_Logs\\log.txt", "C:\\FlashAuto\\Temp\\log.txt", true);
TextReader readLogs = new StreamReader("C:\\FlashAuto\\Temp\\log.txt");
string line = readLogs.ReadLine();
while (line != null)
{
txtExecLog.Text += "\n" + line;
line = readLogs.ReadLine();
txtExecLog.ScrollToEnd();
}
CountLines = txtExecLog.LineCount - 1;
readLogs.Close();
// Forcing the CommandManager to raise the RequerySuggested event
txtExecLog.ScrollToEnd();
CommandManager.InvalidateRequerySuggested();
readLogs.Dispose();
}
else
{
txtExecLog.Text += "log file not found at: "+DateTime.Now.ToString();
}
}
Here is the problem:
Reading and writing to the textbox is successfully done but there is a huge chunk of memory that is eaten up by my app. If I disable the logging, memory usage is optimal.

How to create a Loading Window?

Ok, in my app there are times when loading the DataGridView can take a minute or two. What I want to do is show a GIF in a form with no border until it reaches the end of the loading function. However, if I do:
Views.Loading ldw = new Views.Loading();
ldw.Show();
...
ldw.Close();
...it never actually draws it to the screen and I can't see it. If I do ShowDialog(), it shows the window but never gets past that line of code. I have a feeling it's because it's not a background worker or because the focus gets set back to the parent because of processing...I don't know.
My form is a blank form, added a picture box, added a gif to the picture box, and made FormBorderStyle = none. Any and all help is appreciated.
Update: Current (non-working) Code
private void InitializeBackgroundWorker()
{
//Defines the DoWork Event Handler for _backgroundWorker.
_bgWorkerReports.DoWork += new DoWorkEventHandler(bgWorkerReports_DoWork);
//Defines the RunWorkCompleted Event Handler for _backgroundWorker.
_bgWorkerReports.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgWorkerReports_RunWorkerCompleted);
}
private void bgWorkerReports_DoWork(object sender, DoWorkEventArgs e)
{
ldw.Show();
try
{
string strFilter = "";
if (!_strSearchFilter.Equals(""))
{
strFilter += strFilter.Equals("") ? " " + _strSearchFilter : " and " + _strSearchFilter;
}
if (tvFigure.Nodes.Count > 0)
{
if (_strFigureFilter == "ALL")
{
strFilter += " " + Constants.GetColumnName("Figure") + " LIKE '%%' ";
}
else if (!_strFigureFilter.Equals("") && !_strFigureFilter.Equals(tvFigure.TopNode.Name))
{
if (_strSearchFilter.Equals("") || !cbCurrentFigure.Checked)
{
strFilter += strFilter.Equals("") ? " " + Constants.GetColumnName("Figure") + "='" + _strFigureFilter + "'" : " and " + Constants.GetColumnName("Figure") + "='" + _strFigureFilter + "'";
}
}
}
if (!_strIndentureFilter.Equals(""))
{
strFilter += strFilter.Equals("") ? " " + _strIndentureFilter : " and " + _strIndentureFilter;
}
if (!_strReportFilter.Equals(""))
{
strFilter += (!strFilter.Equals("") ? " and" : "") + " part_id in (" + _strReportFilter + ")";
}
if (strFilter.Length > 0)
{
BindingSource bSource = new BindingSource();
bSource.DataSource = _dataController.PopulateDataGrid(_nViewMode, strFilter).Tables[0];
//Set DataSource to bindingSource for DataGridView.
if (_lstValidationResults.Count > 0)
{
dgvParts.DataSource = _lstValidationResults;
foreach (DataGridViewColumn dc in dgvParts.Columns)
{
dc.DataPropertyName = "ErrorMessage";
dc.Visible = true;
dc.SortMode = DataGridViewColumnSortMode.Programmatic;
dc.AutoSizeMode = DataGridViewAutoSizeColumnMode.ColumnHeader;
}
dgvParts.AutoResizeColumns();
return;
}
else if (!string.IsNullOrEmpty(_strFigureFilter))
{
dgvParts.DataSource = bSource;
dgvParts.Columns[0].Visible = false;
dgvParts.Columns["Description"].Resizable = DataGridViewTriState.False;
dgvParts.Columns["Description"].Width = 750;
}
// Automatically resize the visible rows.
foreach (DataGridViewColumn col in dgvParts.Columns)
{
col.SortMode = DataGridViewColumnSortMode.Automatic;
if (col.Name != "Description")
{
dgvParts.AutoResizeColumn(col.Index);
}
}
dgvParts.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.DisplayedCells;
// Hide the ToolTips for all the cells - redisplay if there is a report.
dgvParts.ShowCellToolTips = true;
// Set the dataGridView control's border.
dgvParts.BorderStyle = BorderStyle.Fixed3D;
// Get and set the ipb_number to the label.
string ipb_number = _dataController.IPBNumber;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void bgWorkerReports_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
ldw.Close();
this.Cursor = Cursors.Default; //Throws error (Cross-thread)
FormatCells();
BuildColumnsComboBox();
int nTotalCount = 0;
foreach (ListViewItem lvi in listView1.Items)
{
int nCount = _lstReportRecords.Where(rr => lvi.Text.Contains(rr.Description)).Count();
nTotalCount += nCount;
lvi.Text = (lvi.Text.Contains("(") ? lvi.Text.Substring(0, lvi.Text.IndexOf("(") + 1) : lvi.Text.Trim() + " (") + nCount.ToString() + ")";
}
rbAllReports.Text = (rbAllReports.Text.Contains("(") ? rbAllReports.Text.Substring(0, rbAllReports.Text.IndexOf("(") + 1) : rbAllReports.Text + " (") + nTotalCount.ToString() + ")";
int nTaggedCount = _lstReportRecords.Where(rr => rr.Description.Contains("Tagged")).Count();
rbTaggedRecords.Text = (rbTaggedRecords.Text.Contains("(") ? rbTaggedRecords.Text.Substring(0, rbTaggedRecords.Text.IndexOf("(") + 1) : rbTaggedRecords.Text + " (") + nTaggedCount.ToString() + ")";
}
Ideally you would have two threads: the GUI thread and the working thread (which can be a BackgroundWorker). Create and show the window in the GUI thread. Handle the loading in the BackgroundWorker's DoWork event. When the loading is done you can call Close() on the load window from the RunWorkerCompleted event and dispose of it.
LoadWindow loadWindow = new LoadWindow();
loadWindow.TopMost = true; // make sure it doesn't get created behind other forms
loadWindow.Show();
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.RunWorkerAsync();
void worker_DoWork(object sender, DoWorkEventArgs e)
{
// do your loading here
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// set DataGridView datasource here
...
// close loading window
loadWindow.Close();
}
The problem you might have with displaying the window could be from the TopMost property, which must be set to true. You can also try calling BringToFront() on the loading window after you've created and shown it.
Yes, BackgroundWorker is for exactly this type of purpose. A couple things to add:
Do not interact with the UI in the worker_DoWork event as it is running on a background thread. Set e.Result when you're finished, which you can check from the RunWorkerCompleted event - or use a form-level variable.
Let any exceptions fall through in the worker_DoWork event and you will see them in the worker_RunWorkerCompleted event in e.Error.
If you need the ability to cancel your load, set worker.WorkerSupportsCancellation and check the e.Cancel while in your DoWork event, then you can check e.Cancelled in your RunWorkerCompleted event.
You should call .Dispose() on your BackgroundWorker when finished.
You'll have to run the code to fill the grid on another thread. Something like:
// Set the picturebox loading state, resize the form etc.
PictureBox.SetLoadingImage();
// Initialize a new thread
Thread t = new Thread(new ThreadStart(() =>
{
// Fill the gridview here
GridView1.DataSource = FillWithData();
GridView1.DataBind();
// When finished, reset the picturebox on it's own thread
PictureBox.Invoke((MethodInvoker)(()=> PictureBox.ClearLoadingImage() ));
}));
// Run the thread.
t.Start();

Categories

Resources