Chart Upgrade in C# make Lagging Application - c#

WindowForm Application, i'm trying to use chart for displaying Datafrom serial port connected to an arduino.
I can read my data and save them to a table in an array after formating the serial data :
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
if (serialPort1.IsOpen)
{
serialDataIn = serialPort1.ReadExisting();
this.Invoke(new EventHandler(ShowData));
}
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void ShowData(object sender, EventArgs e)
{
var charsToRemove = new string[] { "\r" };
foreach ( var c in charsToRemove)
{
serialDataIn = serialDataIn.Replace(c, string.Empty);
}
data = serialDataIn.Split('\n');
data = data.Take(data.Count() - 1).ToArray();
if(pulse_Generated==true)
{
dataPulse = data;
dataMultiPulse = dataMultiPulse.Concat(dataPulse).ToArray();
pulse_Generated = false;
Display_MultiPulse();
Display_Pulse();
}
Display();
}
After than, i'm trying to update 3 chart.
The first one is updated after each data reception (~500ms):
private void Display()
{
chSignal.Series.Clear();
chSignal.Series.Add("Serie1");
chSignal.Series[0].ChartType = SeriesChartType.Line;
// Add point to chart
for (int j = 0; j < data.Length; j++)
{
chSignal.Series[0].Points.AddXY(j, data[j]);
}
Array.Clear(data, 0, data.Length);
//Temporisation pour l'affichage
Thread.Sleep(500);
Restart_Measure();
}
The seconde and the third one are updated after à click button (Pulse generation):
*Seconde one*
private void Display_Pulse()
{
chPulse.Series.Clear();
chPulse.Series.Add("Serie1");
chPulse.Series[0].ChartType = SeriesChartType.Line;
// Add point to chart
for (int j = 0; j < dataPulse.Length; j++)
{
chPulse.Series[0].Points.AddXY(j, dataPulse[j]);
}
Array.Clear(dataPulse, 0, dataPulse.Length);
//Temporisation pour l'affichage
Thread.Sleep(500);
}
*Third one*
private void Display_MultiPulse()
{
var graphDonnee = chMultiPulse.ChartAreas[0];
graphDonnee.AxisX.Maximum = dataMultiPulse.Length - 1;
chMultiPulse.Series.Clear();
chMultiPulse.Series.Add("Serie1");
chMultiPulse.Series[0].ChartType = SeriesChartType.Line;
// Add point to chart
for (int j = 0; j < dataMultiPulse.Length; j++)
{
chMultiPulse.Series[0].Points.AddXY(j, dataMultiPulse[j]);
}
}
The first two work normaly. But the third one updating only when i stop the serial communication betwin my WinFormApp and my arduino.
Further, when a want to generate a "pulse" commande. Normaly i write in a rich text box the pulse characteristic. And the rich text box only update when i stoped the serial communication (as the third chart).
My question is, where my code become blocking ? I go 2 chart out of 3 that work fine.

Related

How to use Progress Bar Form button click events when data is loading in my class

I have a class to load some data from a file and a progress bar form to show the process. My class uses a for loop to load data with a selected buffer size and sets the progress bar value in each loop.
I want to add a cancel and pause button to my form, but when my class starts loading data, the form buttons dont work.
I tried using different threads but they can't have access to same element.
How can I make it so that buttons work when data is loading?
Note: user can select the read type so there are different methods for each type(double,int,byte)
here is my load function:
for (int count = 0; count < (FileSize / LoadBufferSize); count++)
{
if (_check_click == 2)
{
return convertedData;
}
else if(_check_click==1)
{
return new Int16[1];
}
else
{
int j = 0;
for (int i = 0; i < fileContent.Length; i++)
{
try
{
fileContent[i] = br.ReadInt16();
}
catch (EndOfStreamException)
{
loadflag = 1;
contentSize = i;
break;
}
}
for (int k = 0; k < contentSize; k += ReSampleRate)
{
try
{
convertedData[(count * fileContent.Length / ReSampleRate) + j] = fileContent[k];
j++;
}
catch (IndexOutOfRangeException)
{
MessageBox.Show("could not load the file completely");
goto lable;
}
catch
{
MessageBox.Show("something went wrong");
}
}
progress = ((count + 1) * fileContent.Length ) / (FileSize / 100);
barForm.SetBar((int)progress);
}
}
lable:
{
return convertedData;
}
This might be helpful.
public class Form1 : Form
{
private Queue<string> _items = new Queue<string>(new [] { "A", "B", "C" });
private Button _startButton = new Button() { Text = "Start", Top = 8, Left = 4, Height = 24, Width = 100 };
private Button _pauseButton = new Button() { Text = "Pause", Top = 32, Left = 4, Height = 24, Width = 100 };
private bool _paused = false;
public Form1()
{
_startButton.Click += (s, e) => this.Process();
_pauseButton.Click += (s, e) => _paused = true;
this.Controls.Add(_startButton);
this.Controls.Add(_pauseButton);
}
private void Process()
{
if (!_paused && _items.TryDequeue(out string text))
{
Console.WriteLine(text);
this.Invoke(() => this.Process());
}
}
}
The key thing here is that the private void Process() method has a recursive call to itself through the .Invoke method. This keeps running Process so long as there are items in the queue, but it also lets other events occur in the meanwhile, so if someone clicks the Pause button then the Process method will stop running.
There is no for loop. Just a repeating Process method that responds to any changes in state.

How to show progress while populating dataGridView?

I'm populating datagridview with random numbers from a given range, but when I generate a big amount of numbers - my program hangs while generating them. That could last more that a minute (depending on the amount). I know that I can show a progress using ProgressBar. I've tried to use it, but I haven't got anythin. Any examples of using it?
Here is my code:
private void button1_Click(object sender, EventArgs e)
{
if (dataGridView1.RowCount > 0) {
dataGridView1.Rows.Clear();
dataGridView1.Refresh();
}
N = int.Parse(textBox1.Text);
range_min = int.Parse(textBox2.Text);
range_max = int.Parse(textBox3.Text);
numbers = new int[N];
if (range_max < range_min) MessageBox.Show("Some alert text");
else if (range_max == range_min) MessageBox.Show("Some alert text");
else
{
dataGridView1.RowCount = N;
for (int i = 0; i < N; i++)
{
numbers[i] = (int)(Math.Round((range_max - range_min) * rndm.NextDouble() + range_min));
dataGridView1[0, i].Value = numbers[i];
}
}
}
Your program "hangs" while adding data to the UI because you are doing all the work in the UI thread effectively blocking the thread until your loop is done. So you need to handle this heavy duty work in a seperate thread. But you can only change the UI from the UI/main thread so something like this would throw an exception:
private void button1_Click(object sender, EventArgs e)
{
new Thread(() =>
{
for (int i = 0; i < 4000; i++)
{
dataGridView1.Rows.Add(i.ToString());//throws an exception
}
}).Start();
}
The solution for this is to create a method which you can invoke the main thread to execute like so:
private void button1_Click(object sender, EventArgs e)
{
new Thread(() =>
{
for (int i = 0; i < 10000; i++)
{
this.AddRow(i);
}
}).Start();
}
public void AddRow(int value)
{
if (this.InvokeRequired)
this.Invoke(new MethodInvoker(() => this.AddRow(value)));
else
dataGridView1.Rows.Add(value.ToString());//do your ui update (add row, update progress bar etc..)
}

datagrid get selected rows and cells values in wpf c#

I would like to redo the code of my old windows forms application on wpf and I have a problem with referencing datagridview.
This is the void look of my old application:
private void button2_Click(object sender, EventArgs e)
{
if (DGV1.Rows.Count > 0 && DGV1.SelectedRows != null)
{
bool wart = true;
for (int i = 0; i < listBox2.Items.Count; i++)
{
listBox2.SelectedIndex = i;
int w1 = Int32.Parse(listBox2.SelectedItem.ToString());
int w2 = Int32.Parse(DGV1.SelectedRows[0].Cells[0].Value.ToString());
if (w1 == w2)
{
wart = false;
break;
}
}
if (wart)
{
listBox2.Items.Add(DGV1.SelectedRows[0].Cells[0].Value);
}
}
}
This is the void look of my new application:
private void Button1_Click(object sender, RoutedEventArgs e)
{
IList rows = dataGrid1.SelectedItems;
if(dataGrid1.SelectedItem != null)
{
bool wart = true;
for (int i =0; i < listBox1.Items.Count; i++)
{
listBox1.SelectedIndex = i;
object item = dataGrid1.SelectedItem;
int w1 = Int32.Parse(listBox1.SelectedItem.ToString());
int w2 = Int32.Parse(dataGrid1.SelectedCells[0].Column.GetCellContent(item).ToString()); <--- !!
if(w1 == w2)
{
wart = false;
break;
}
}
if(wart)
{
listBox1.Items.Add(dataGrid1.SelectedCells[0]); <-- !!
}
}
}
The application spills out at the second if, where it displays:
And it should be:
Please Help :-)
It should probably be like this:
listBox1.Items.Add(dataGrid1.CurrentRow.Cells[0].Value);
This code is from WinForms, but I assume the coding for wpf may not be different, since both are in c#.
dataGrid1.SelectedItem isn't just some object, it has concrete type and properties like Id, Tytul, Kategorie, Text
you need to make a cast to that concrete type and access property instead of trying to get the value from low-level UI elements like DataGridCellInfo:
var item = (MyConcreteClass)dataGrid1.SelectedItem;
int w2 = item.Id;

.net - How to add controls dynamically?

I want to add dynamic controls
Like the below image I want to do
I am struggling to do that
If I click Add More Experience button I want to display another rows
I tried with user control but it is not working properly.
Below code is working fine but if I add controls then close the browser page and then open the browser again added controls are coming.
I think the problem is static int i=0;
static int i = 0;
protected void addnewtext_Click(object sender, EventArgs e)
{
i++;
for (int j = 0; j <= i; j++)
{
AddVisaControl ac = (AddVisaControl)Page.LoadControl("AddVisaControl.ascx");
placeHolder.Controls.Add(ac);
placeHolder.Controls.Add(new LiteralControl("<BR>"));
}
}
Please provide your ideas? Thanks in advance
As per my comment, when using a static variable within an ASP.Net page, it will be shared amongst all users until the application pool or server is restarted.
Instead you should really be using a ViewState or similar to read/write the value.
private int controlCount
{
get
{
int val = 0;
try
{
val = (int)Page.ViewState["ControlCount"];
}
catch(Exception e)
{
// handle exception, if required.
}
return val;
}
set { Page.ViewState["ControlCount"] = value; }
}
protected void addnewtext_Click(object sender, EventArgs e)
{
int i = controlCount++;
for (int j = 0; j <= i; j++)
{
AddVisaControl ac = (AddVisaControl)Page.LoadControl("AddVisaControl.ascx");
placeHolder.Controls.Add(ac);
placeHolder.Controls.Add(new LiteralControl("<BR>"));
}
}

How can I invert the selected items in multiple listboxes using only one for loop?

I am using three list boxes. I have to invert the selected items in all the list boxes using an invert button.
How can code it using only a single loop? There can be more than 3 list boxes as well.
Hi you could use this function to invert the selection for a given listbox.
/* Windows ListBox
public void InvertSelection(ListBox objLstbox)
{
if(objLstbox == null) return;
for (int i = 0; i < objLstbox.Items.Count; i++)
objLstbox.SetSelected(i, !objLstbox.GetSelected(i));
}
*/
//WebApp listbox
public void InvertSelection(ListBox objLstbox)
{
if (objLstbox == null) return;
for (int i = 0; i < objLstbox.Items.Count; i++)
objLstbox.Items[i].Selected = !objLstbox.Items[i].Selected;
}
private void btnInvert_Click(object sender, EventArgs e)
{
InvertSelection(listBox1);
InvertSelection(listBox2);
InvertSelection(listBox3);
}
public void InvertSelection(ListBox objLstbox)
{
if (objLstbox == null) return;
for (int i = 0; i < objLstbox.Items.Count; i++)
objLstbox.Items[i].Selected = !objLstbox.Items[i].Selected;
}
protected void Button1_Click(object sender, EventArgs e)
{
InvertSelection(ListBox1);
}
I banged my head on this with the rest of you, and finally developed my own function for Inverting
Here's the VB.Net Answer:
Private Function InvertListBoxSelections(ByRef tempListBox As ListBox) As Integer
Dim selectedind(tempListBox.SelectedItems.Count) As Integer
Try
For selind = 0 To tempListBox.SelectedItems.Count - 1
selectedind.SetValue(tempListBox.Items.IndexOf(tempListBox.SelectedItems(selind)), selind)
Next
tempListBox.ClearSelected()
For listitemIndex = 0 To tempListBox.Items.Count
If Array.IndexOf(selectedind, listitemIndex) < 0 Then
tempListBox.SetSelected(listitemIndex, True)
End If
Next
Return 1
Catch ex As Exception
Return 0
End Try
End Function
for (int i = 0; i < listbox.Items.Count; i++)
{
if (listbox.SelectedItems.Contains(listbox.Items[i]))
listbox.SetSelected(i, false);
else
listbox.SetSelected(i, true);
}
Since I got here and got confused by selection i'll leave this here.
This code inverts all checked items by using .SetItemChecked and .GetItemChecked:
private void ButtonInvertChecked_Click(object sender, EventArgs e)
{
for (int i = 0; i < checkedListBox.Items.Count; i++)
checkedListBox.SetItemChecked (i, !checkedListBox.GetItemChecked(i));
}

Categories

Resources