C# - Visual Studio - How can I make chart update in real time? - c#

basically im making a gui that shows a chart, and has a database.
the database table has 2 fields: Id, and Price
I'm trying to make the chart a line chart that updates and keeps the past 50 or so x values, but it keeps being a bar chart and it includes all the information, it wont truncate to only max 50 'x-values':
// create database/tables
StockDBDataSet_JEROTableAdapters.TableTableAdapter JERO_table = new StockDBDataSet_JEROTableAdapters.TableTableAdapter();
// loop indefinitely changing prices per duration set
for (int i = 1; i < 100; i++)
{
chrtJERO.Series.Clear();
chrtJERO.DataBindTable(JERO_table.GetData(), "Id");
JERO_table.Insert(i, JERO.Price);
JERO.ChangePrice();
await Task.Delay(100);
}
what am i doing wrong? btw I'm a beginner in C#, if that helps with context.
Thanks!

Related

C# PDF table add row in wrong position

[EDIT due to misunderstanding of the answer]
I'm doing a simple program in C# with PDF file creation with iText7.
In this PDF i'm adding a table whose first cell starts at a certain position in the file.
I don't know if I set the position correctly, but everytime I add another cell with tab.StartNewRow() the resulting new table is repositioned taking THAT last cell as position reference, putting the previously added cells from that point up, while I want to add the cells from that point down.
Which method should I use? That's my code:
Previously I set the position of the first table cell using tab1.SetFixedPosition(20, heigh, width);
and then, in order to add the other cells:
if (mylistbox.Items.Count > 0)
{
tab1.AddCell("FIRST CELL");
tab1.StartNewRow();
for (int i = 0; i < mylistbox.Items.Count; i++)
{
tab1.AddCell(mylistbox.Items[i].ToString());
tab1.StartNewRow();
}
doc.Add(tab1);
}
[EDIT #2] in order to explain my issue better
I have to put 5 tables, which have to grow from a certain point DOWN, positioned at equal distances, same height and width in the doc. This image explains how it should result:
In a WPF application, I have a ListBox with 5 items, numbered 1 through 5. This should be very similar to WinForms.
The CreatePercentArray takes a size which is equal to the amount of columns in a row.
An interesting article about tables: link
private void CreateListBoxTable(Document pdfDoc)
{
// Create an array where each item has an equal width, and use the entire pdf width
// The CreatePercentArray takes a size which is equal to the amount of columns in a row
// By using percentages, they will automatically adapt
// Use CreatePointArray for exacter measurements
var table = new Table(UnitValue.CreatePercentArray(2)).UseAllAvailableWidth();
if (!MyListBox.Items.IsEmpty)
{
foreach (var listBoxItem in MyListBox.Items)
{
table.AddCell(((ListBoxItem) listBoxItem).Content.ToString());
}
}
// Adds table to document
pdfDoc.Add(table);
// Closes document
pdfDoc.Close();
}

C# WindowsForm Add DatagridView Content into PowerPoint's slide

I'm working wth .NET 4.7.2, Windowsform.
I have a datagridview and I manage to generate a powerpoint file pptx.
I made a first ppt slide and I'd like to add the datagridview content into the second ppt slide given that I need to have the option to change the data within the PPt slide.
Microsoft.Office.Interop.PowerPoint.Application pptApp = new Microsoft.Office.Interop.PowerPoint.Application();
pptApp.Visible = Microsoft.Office.Core.MsoTriState.msoTrue;
Microsoft.Office.Interop.PowerPoint.Slides slides;
Microsoft.Office.Interop.PowerPoint._Slide slide;
Microsoft.Office.Interop.PowerPoint._Slide slide2;
Microsoft.Office.Interop.PowerPoint.TextRange objText;
// Create File
Presentation pptPresentation = pptApp.Presentations.Add(Microsoft.Office.Core.MsoTriState.msoTrue);
CustomLayout customLayout = pptPresentation.SlideMaster.CustomLayouts[PpSlideLayout.ppLayoutText];
// new Slide
slides = pptPresentation.Slides;
slide = slides.AddSlide(1, customLayout);
slide2 = slides.AddSlide(1, customLayout);
// title
objText = slide.Shapes[1].TextFrame.TextRange;
objText.Text = "Bonds Screner Report";
objText.Font.Name = "Haboro Contrast Ext Light";
objText.Font.Size = 32;
Shape shape1 = slide.Shapes[2];
slide.Shapes.AddPicture("C:\\mylogo.png", Microsoft.Office.Core.MsoTriState.msoFalse, Microsoft.Office.Core.MsoTriState.msoTrue, shape1.Left, shape1.Top, shape1.Width, shape1.Height);
slide.NotesPage.Shapes[2].TextFrame.TextRange.Text = "Disclaimer";
dataGridViewBonds.ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableAlwaysIncludeHeaderText;
dataGridViewBonds.SelectAll();
DataObject obj = dataGridViewBonds.GetClipboardContent();
Clipboard.SetDataObject(obj, true);
Shape shapegrid = slide2.Shapes[2];
I know I'm not so far by now but I miss smething. Any help would be appreciated !
I am familiar with Excel interop and have used it many times and most likely have become numb to the awkward ways in which interop works. Using PowerPoint interop can be very frustrating for numerous reasons, however, the biggest I feel is the lack of documentation and the differences between the different MS versions.
In addition, I looked for a third-party PowerPoint library and “Aspose” looked like the only option, unfortunately it is not a “free” option. I will assume there is a free third-party option and I just did not look in the right place… Or there may be a totally different way to do this possibly with XML. I am confident I am preaching to the choir.
Therefore, what I have been able to put together may work for you. For starters, looking at your current posted code, there is one part missing that you need to get the “copied” grid cells into the slide…
slide.Shapes.Paste();
This will paste the “copied” cells from the grid into an “unformatted” table into the slide. This will copy the “row header” if it is displayed in the grid in addition to the “new row” if the grids AllowUserToAddRows is set to true. If this “unformatted paste” works for you, then you are good to go.
If you prefer to have at least a minimally formatted table and ignore the row headers and last empty row… It may be easier to simply “create” a new Table in the slide with the size we want along with the correct number of rows and columns. Granted, this may be more work, however, using the paste is going require this anyway “IF” you want the table formatted.
The method (below) takes a power point _Slide and a DataGridView. The code “creates” a new Table in the slide based on the number of rows and columns in the given grid. With this approach, the table will be “formatted” using the default “Table Style” in the presentation. So, this may give you the formatting you want by simply “creating” the table as opposed to “pasting” the table.
I have tried to “apply” one of the existing “Table Styles” in power point, however, the examples I saw used something like…
table.ApplyStyle("{5C22544A-7EE6-4342-B048-85BDC9FD1C3A}");
Which uses a GUID id to identify “which” style to use. I am not sure why MS decided on this GUID approach… this is beyond me, and it worked for “some” styles but not all.
Also, more common-sense solutions that showed something like…
table.StylePreset = TableStylePreset.MediumStyle2Accent2;
Unfortunately using my 2019 version of Office PowerPoint, this property does not exist. I have abandoned further research on this as it appears to be version dependent. Very annoying!
Given this, it may be easier if we format the cells individually as we want. We will need to add the cells text from the grid into the individual cells anyway, so we could also format the individual cells at the same time. Again, I am confident there is a better way, however, I could not find one.
Below the InsertTableIntoSlide(_Slide slide, DataGridView dgv) method takes a slide and a grid as parameters. It will add a table to the slide with data from the given grid. A brief code trace is below.
First a check is made to get the number of total rows in the grid (not including the headers) totRows. If the grids AllowUsersToAddRows is true, then the total rows variable is decremented by 1 to ignore this new row. Next the number of columns in the grid is set to the variable totCols. The top left X and Y point is defined topLeftX and topLeftY to position the table in the slide along with the tables width and height.
ADDED NOTE: Using the AllowUserToAddRows property to determine the number of rows … may NOT work as described above and will “miss” the last row… “IF” AllowUserToAddRows is true (default) AND the grid is data bound to a data source that does NOT allow new rows to be added. In that case you do NOT want to decrement the totRows variable.
Next a “Table” “Shape” is added to the slide using the previous variables to define the base table dimensions. Next are two loops. The first loop adds the header cells to the first row in the table. Then a second loop to add the data from the cells in the grid… to the table cells in the slide.
The commented-out code is left as an example such that you want to do some specific formatting for the individual cells. This was not need in my case since the “default” table style was close to the formatting I wanted.
Also, a note that “ForeColor” is the “Back ground” color of the cell/shape. Strange!
I hope this helps and again, sympathize more about having to use PowerPoint interop… I could not.
private void InsertTableIntoSlide(_Slide slide, DataGridView dgv) {
try {
int totRows;
if (dgv.AllowUserToAddRows) {
totRows = dgv.Rows.Count - 1;
}
else {
totRows = dgv.Rows.Count;
}
int totCols = dgv.Columns.Count;
int topLeftX = 10;
int topLeftY = 10;
int width = 400;
int height = 100;
// add extra row for header row
Shape shape = slide.Shapes.AddTable(totRows + 1, totCols, topLeftX, topLeftY, width, height);
Table table = shape.Table;
for (int i = 0; i < dgv.Columns.Count; i++) {
table.Cell(1, i+1).Shape.TextFrame.TextRange.Text = dgv.Columns[i].HeaderText;
//table.Cell(1, i+1).Shape.Fill.ForeColor.RGB = ColorTranslator.ToOle(Color.Blue);
//table.Cell(1, i+1).Shape.TextFrame.TextRange.Font.Bold = Microsoft.Office.Core.MsoTriState.msoTrue;
//table.Cell(1, i+1).Shape.TextFrame.TextRange.Font.Color.RGB = ColorTranslator.ToOle(Color.White);
}
int curRow = 2;
for (int i = 0; i < totRows; i++) {
for (int j = 0; j < totCols; j++) {
if (dgv.Rows[i].Cells[j].Value != null) {
table.Cell(curRow, j + 1).Shape.TextFrame.TextRange.Text = dgv.Rows[i].Cells[j].Value.ToString();
//table.Cell(curRow, j + 1).Shape.Fill.ForeColor.RGB = ColorTranslator.ToOle(Color.LightGreen);
//table.Cell(curRow, j + 1).Shape.TextFrame.TextRange.Font.Bold = Microsoft.Office.Core.MsoTriState.msoTrue;
//table.Cell(curRow, j + 1).Shape.TextFrame.TextRange.Font.Color.RGB = ColorTranslator.ToOle(Color.Black);
}
}
curRow++;
}
}
catch (Exception ex) {
MessageBox.Show("Error: " + ex.Message);
}
}

Cannot display labels for specific data points in MSChart

I want to display labels for specific data points in MSChart pie chart winform application with the following code
if (Accountchart.Series[0].Points.Count > 0)
{
for (int i = 0; i < Accountchart.Series[0].Points.Count; i++)
{
double calc=(yValues[i] * 100 / (double)totalTimeSpent);
if ( calc< 10.00)
Accountchart.Series[i].Points[i]["PieLabelStyle"] = "Disabled";
}
}
But getting the following error while executing the code segment in if block second time
[Screenshot]![1
You probably ONLY have Series[0], I guess.
Series[i] looks like a mistake to me - in the whole context of this code.
So, when i==1 (the second time through), the Series[i] does NOT exist! Thus the exception, cause index is out of range.
But it is only a guess!
I think You in fact wanted to write: Series[0]....... in the IF-command, just like in the lines above the for loop.

TeeChart Colorgrid Performance with lots of Data Points

I am writing an application in Visual Studio Express [C#], and I need to display 12 ColorGrids [128 x 128] at the same time, in realtime.
This is how I setup my chart:
tChart1.Aspect.View3D = false;
tChart1.Aspect.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed;
tChart1.Legend.Visible = false;
tChart1.Axes.Bottom.Title.Text = "R";
tChart1.Axes.Bottom.SetMinMax(0, 127);
tChart1.Axes.Bottom.Increment = 20;
tChart1.Axes.Left.Title.Text = "D";
tChart1.Axes.Left.SetMinMax(0, 127);
And then I init the ColorGrid like this:
for (int d = 0; d < 128; d++)
{
for (int r = 0; r < 128; r++)
{
ColorGrid.Add(r, 0, d);
}
}
And then, in realtime, all I do is I update the YValues in some for-loop which covers the complete 128 x 128 range:
ColorGrid.YValues[index] = value;
And after the for loop, I call:
ColorGrid.BeginUpdate();
ColorGrid.EndUpdate();
I currently have this for 12 TChart controls, which are displayed together on a Form.
I also tried combining the 12 charts into one big chart, by plotting 12 graphs as a 6 x 2 "sub-plot" graph, and that only made a small performance difference.
Is there a way to get 10+fps with:
either 12 separate [128 x 128] graphs, or one [128*6 x 128*2] graph???
If I have left anything unclear, please let me know :-)
Thank you
JD
To improve the ColorGrid drawing time is a feature request already present in Steema's wish list (TF02016286).
Also note that, in general, as more points and elements of the chart to be drawn (grid lines, gradients, etc) more time is needed to draw the chart. So I'm not sure if it can be improved to the point you require.
A tip I don't see implemented in your example is to hide the ColorGrid Pen. This improves a bit the performance:
ColorGrid.Pen.Visible = false;
Also note ColorGrid.BeginUpdate() and ColorGrid.EndUpdate() are thought to be called before and after Clearing and repopulating the series respectively, not both together and after modifying the series values.

multiple hits in loop after the break command

I've got a strange problem. I'm creating a NUI for application and I binded some simple gestures to right and left arrow. The problem is when I start application. When I make gesture for the first time my application is hitting 2 times in a row. After that it works 100% as I want. Only the start is the problem.
I'm adding two Joints and timestamp to my history struct which is put into the ArrayList
this._history.Add(new HistoryItem()
{
timestamp = timestamp,
activeHand = hand,
controlJoint = controlJoint
}
);
then in foreach loop I'm comparing data
if (Math.Abs((hand.Position.X - item.controlJoint.Position.X)) < MainWindow.treshold && Math.Abs((hand.Position.Y - item.controlJoint.Position.Y)) < MainWindow.verticalTreshold)
If it hits I instantly break the lopp with
break;
after that I clear the history ArrayList
this._history.Clear();
So I don't get it. Why after the start it hits two times in a row ?
// edit
history ArrayList initialization
private List<HistoryItem> _history = new List<HistoryItem>(16);
in loop
foreach (HistoryItem item in this._history)
{
if ((hand.Position.X - item.controlJoint.Position.X) < MainWindow.treshold)
{
float tmp = (hand.Position.X - controlJoint.Position.X);
MainWindow.slideNumber++;
this._logger.Log("Next slide: " + MainWindow.slideNumber);
this._logger.Log(hand.Position.X + " - " + controlJoint.Position.X + " = " + tmp + " | " + MainWindow.treshold);
this.startTime = 0;
this.gestureStart = false;
answerFlag = true;
System.Windows.Forms.SendKeys.SendWait("{Right}");
break;
}
}
Now. As you can see i'm breaking here. So this code shouldn't be invoked second time in a row
How this clears something
// edit 2
I'll also add that to get into this part of code the gestureStart flag need to be set to true. As you can see after getting into the 'if' part here I'm setting it to false. So it is impossible that the code instantly can get to this part
// edit 3 WORKING WORKAROUND
I've created kind of workaround. I've added time control. I'm comparing timestamp of invoking the code and timestamp of last gesture recognition. If its too fast ( i meen couple of ms which it impossible to make ) I don't allow to hit an arrow. I'm not sure if it's a perfect solution but it is a working solution
Ok my problem was the code. Ofc a small bug untracable in the debug. I used one function to analyse a history of frames.
The method was working in 2 modes. I`ve detached that and created 2 diffrent methods, each for each task and now it works great

Categories