how to display labels like a running sequence ? C# - c#

I am trying to do "running window" like for labels. I tried to find similar solution in the google but it got me nowhere.
EXAMPLE: 5 numbers needed to be displayed at different counter values. This was macro to my timer_Start() thus, the counter increases every 5 seconds which was set at my main form.
Display: 21 23 24 25 26
If I insert another value, eg. 23, the last 5 number should be displayed.
Display: 23 21 23 24 25 ,
However, for my code below, when I insert another value, all 5 of them will change. If i change to if(counter == 2), it unable to get update when the counter == 3.
int counter = 0;
sql_cmd = sql_conn.CreateCommand();
sql_cmd.CommandText = "SELECT * FROM temp where id=12";
try
{
sql_conn.Open();
sql_reader = sql_cmd.ExecuteReader();
while (sql_reader.Read()) // start retrieve
{
if (counter >= 1)
{
this.avg1.Text = sql_reader["Temp1"].ToString();
}
}
sql_conn.Close();
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
if (counter >= 2)
{
avg2.Text = avg1.Text;
}
if (counter >= 3)
{
avg3.Text = avg2.Text;
}
if (counter >= 4)
{
avg4.Text = avg3.Text;
}
if (counter >= 5)
{
avg5.Text = avg4.Text;
counter = 0;
}
Any help is much appreciated. Thanks.

Your problem is with your series of if statements. Simple debugging would allow you to see this, so I would suggest stepping through your code before coming here next time. With that, your IF statements can be refracted out into a simple method for you to use.
private void UpdateLabels(string newValue) {
avg5.Text = avg4.Text;
avg4.Text = avg3.Text;
avg3.Text = avg2.Text;
avg2.Text = avg1.Text;
avg1.Text = newValue;
}
What is important here is that you have the correct update order. Your original if statements where not in the correct order, which would be why you were having issues. If you want to see why this works, walk through both sets of code in a debugger and see how the Label.Text properties change.
Now you can call this new method after you get your new value from the database... Here we can update your timer code to be slightly better.
sql_cmd = sql_conn.CreateCommand();
sql_cmd.CommandText = "SELECT * FROM temp where id=12";
string newValue = String.Empty;
try {
sql_conn.Open();
sql_reader = sql_cmd.ExecuteReader();
while (sql_reader.Read()) {
newValue = sql_reader["Temp1"].ToString(); // store in local variable
}
} catch (Exception e) {
MessageBox.Show(e.Message);
} finally {
sql_conn.Close(); // SqlConnection.Close should be in finally block
}
UpdateLabels(newValue);
First there is no need for a counter anymore (based off your original code you posted, it was never needed). Since Label.Text can accept blank strings, you can always copy the values, regardless if its the first update or one millionth.
Second you can store your database value in a temporary variable. This will allow you to update the Labels even if there is a database error. After all the database operations are finished, you then call UpdateLabels with your new value and you are all set.

Related

Why does my Array always have 0s in it when it should have nothing in it - C#

I'm working on something for school, just a basic score calculator. I know it's not the prettiest code, but it works and that's more what the class is focused on here at the beginning.
The only issue that I have is that whenever I click "Display" it prints out 20 0s. 20 is the length of the array. Everything else is working. It adds the number I input into the array and replaces the 0s. But I don't want it to have 0s at all unless I specifically type them in.
Any help is appreciated.
Full code:
// Creates the list that displays the score
List<string> scoreList = new List<string>();
// Array to store up to 20 scores
int[] scoreArray = new int[20];
// class level variable to store current open slot in the array
int openSlot = 0;
public Form1()
{
InitializeComponent();
}
// Initializes variables that hold our math total and count of numbers entered
int total = 0;
int count = 0;
private void btnExit_Click(object sender, System.EventArgs e)
{
this.Close();
}
private void btnAdd_Click(object sender, System.EventArgs e)
{
if (openSlot <= scoreArray.GetUpperBound(0))
{
try
{
// Basic math for conversion of entered number and calculating total numbers entered
// and the averages of those numbers
int score = Convert.ToInt32(txtScore.Text);
total += score;
count += 1;
int average = total / count;
txtScoreTotal.Text = total.ToString();
txtScoreCount.Text = count.ToString();
txtAverage.Text = average.ToString();
txtScore.Focus();
}
catch(System.FormatException) // Makes sure that the user enters valid character into box
{
MessageBox.Show("Please enter valid number into box");
return;
}
// Adds the most recent entered number to the Score List
scoreList.Add(txtScore.Text);
}
// if statement to make sure that there is still room in the array to store the
// new entry
if (openSlot > scoreArray.GetUpperBound(0)) // GetUpperBound(0) returns the index of the last element in the first dimension
{
MessageBox.Show("The array is full! The most recent number was not added.");
txtScore.SelectAll();
txtScore.Focus();
return;
}
// Assigns a variable as an integer from the score text box
// to allow us to numerically sort the numbers in the scoreArray
int scoreParse = Int32.Parse(txtScore.Text);
// move the most recent number to the current open slot in the score array
scoreArray[openSlot] = scoreParse;
// add 1 to openSlot
openSlot += 1;
}
private void btnClear_Click(object sender, EventArgs e)
{
// Clears all input fields and resets variables to 0
openSlot = 0;
total = 0;
count = 0;
txtScore.Text = "";
txtScoreTotal.Text = "";
txtScoreCount.Text = "";
txtAverage.Text = "";
txtScore.Focus();
// Clears the array and list
int[] clearScoreArray = new int[20];
scoreArray = clearScoreArray;
List<string> clearScoreList = new List<string>();
scoreList = clearScoreList;
}
private void btnDisplay_Click(object sender, EventArgs e)
{
// If array has no stored values, display a MessageBox that informs user
if (scoreArray == null || scoreArray.Length == 0)
{
MessageBox.Show("There are no numbers to display");
return;
}
//move focus to the code textbox
txtScore.Focus();
// Creates a blank string variable named scr to input the scores into
// for the MessageBox
string scr = "";
foreach (var scoreAdded in scoreArray)
{
// Adds variable scr as the string to display
scr += scoreAdded + "\n";
}
// Sorts the array from lowest to highest number
Array.Sort(scoreArray);
// Displays a message box with the scores that were added
MessageBox.Show(scr);
}
}
When you declare a set amount of arrays (In your place it's 20), they get some sort of value, normally it's 0. Keep this is mind when you are using myArrayHere.length, cause it will check how many arrays have been declared (int[] array) and initialized (... = new array[]), not how many have been modified (given a value).
Best solution, IMO is creating a function, that would know how many elements in an array you will need or how many of them you are using (just have a function, that returns the amount of used variables, by checking it with a loop, and then modifying it later on... but that is one way to fix this issue, and there are better fixes than these I pointed out, but as I see you are newer to C# (prob.) fixing your issues with ok'ish code is good, as your first project should be meant for learning, later on, you can improve it and heck, if you are looking to become a pro, take some Programming courses on how to improve your code in general).
Good luck!
-Normantas
You can use nullable if you dont want zero as default value.
int? [] array = new int?[20] ;
Welcome to SO!
When an object is initially declared there is a default initialization value. In this case, 0 is the default value for an int in C#. The default value can often be changed at the initialization of the object if there's a supporting constructor.
When the int[] scoreArray = new int[20]; is declared, all 20 variables are assigned the value of 0. This is because C# does not allow uninitialized variables.
This link shows all default initialization values for C#.
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/default-values-table

Slow write and inconsistant write to MongoDB via C#

Problem:
We are experiencing slow write and the time varies greatly between writes. From just over 1 minute to almost 4 minutes. This is to insert a large amount of values (704 974 to be precise)
Background:
We read the values in from a txt file, link it to a certain tag (data object) and then add the values to a value collection. Each data point is linked to a tag and a time. Each value bson has two primary keys: ID, and tag-date.
The value Bson looks as follows:
{
"_id" : ObjectId,
"Timestamp" : ISODate,
"TagID" : ObjectId,
"Value" : string or double,
"FileReferenceID" : ObjectId,
"WasValueInterpolated" : int
}
The mongoDb is set as a 3 replication set, and we write with writeconcern true (we have had trouble where one replicating set would fall behind and refuse to auto catch up) The Mongo's run on a MESOS/Linux deployment, while the c# code connects over the network from a windows machine.
Mongo version: 3.4.5
C# driver: 2.4.4
I have also increased the min and max threadpool thread counts by 50. I leverage threads to try and increase the write speed, it somewhat works.
Code
The actual piece of the code that inserts the data into mongo is this:
public int InsertValues(string aDatabaseName, List<cValueDocument> aValues, out List<int> aErrorValueIndexes,
bool aOverride = false)
{
Parallel.ForEach(aValues, aValue => aValue.ConvertToDoubleIfCan());
int lResult = 0;
Stack<int> lErrorIndexesToDelete = new Stack<int>(aValues.Count - 1);
aErrorValueIndexes = new List<int>(aValues.Count);
aDatabaseName = aDatabaseName.ToLower();
var lValueCollection =
MongoDatabasesDict[aDatabaseName].GetCollection<cValueDocument>(tMongoCollectionNames.Value.ToString());
var lTagCollection =
MongoDatabasesDict[aDatabaseName].GetCollection<cTagDocument>(tMongoCollectionNames.Tag.ToString());
List<cValueDocument> lValuesOrderedByTime = aValues.OrderBy(aDocument => aDocument.Timestamp).ToList();
// Check if there are Values that belong to other Tags.
if (lValuesOrderedByTime.Any(aValue => aValue.TagID != lValuesOrderedByTime[0].TagID))
{
return -4;
}
cTagDocument lTagDocument = lTagCollection.AsQueryable().First(aTag => aTag._id == lValuesOrderedByTime[0].TagID);
// Find any Values that are not at least the minimum Interval between each other.
for (int i = 1; i < lValuesOrderedByTime.Count; i++)
{
// Determine if the two consecutive timestamps are not at least an Interval from each other.
if (lTagDocument.IntervalMask.CompareDateTimesWithinInterval(lValuesOrderedByTime[i - 1].Timestamp, lValuesOrderedByTime[i].Timestamp) == -1)
{
aErrorValueIndexes.Add(aValues.FindIndex(aElement => aElement == lValuesOrderedByTime[i]));
lErrorIndexesToDelete.Push(i);
lResult = -2;
}
}
// Determine if erroneous values must be removed before insertion.
if (lResult == -2)
{
// Remove each value with an index in lErrorIndexesToDelete;
while (lErrorIndexesToDelete.Count > 0)
{
lValuesOrderedByTime.RemoveAt(lErrorIndexesToDelete.Pop());
}
}
if (aOverride)
{//removed for testing purposes}
try
{
try
{
InsertManyOptions lOptions = new InsertManyOptions();
lOptions.IsOrdered = false;
lValueCollection.InsertMany(lValuesOrderedByTime, lOptions);
}
catch (MongoBulkWriteException lException)
{
if (lException.WriteErrors?.First().Code == 11000)
{
aErrorValueIndexes = Enumerable.Range(0, aValues.Count).ToList();
lResult = -3;
}
else
{
throw;
}
}
return lResult;
}
catch (Exception lException)
{
BigDBLog.LogEvent("Error, an exception was thrown in InsertValues. ", tEventEscalation.Error,
false,
lException);
return -5;
}
}
I removed some of the value checking to shorten the function.
Basically the function pushes aValues to the mongo
Debug/Tracing
Here is where it gets a strange for me. I use the same file to test it. I delete the values from the DB before each test.
The executing speed goes from just over 1 minute to just below 4 minutes.
I did a trace on the program using jetbrains dotTrace. It points to MongoDB.Driver.Core.Misc.StreamExtensionMethods.ReadBytes as the hot spot. If you follow the code, this was called form MongoDB.Driver.MongoCollectionBase`1.InsertMany. This is weird as I am writing the the DB and not reading from it. The CPU uses does spike (more during the translation of the file), but stays low (1-2%).
I have checked the wiredTiger.concurrentTransactions tickets. They dont run out.
Questions
How can I improve my read speed (at worst 3175 values/s, at best
8392 values/s)?
Why do I have such inconsistencies? I dont really believe it can all be network related.
Why does it read bytes so much and why is it causes
a bottleneck?
What can I further do to help find the problem?

C# Accessing an array of labels from another form and altering their "Text" property

This is my first post. So..critique is always welcomed.
My question is straight forward just by looking at the title.
How can I use a loop to insert values to different labels by using their reference (get,set methods are in a different form)
What I've tried is to create an array with the references of the labels. The thing is.. it assigns the new values to the array rather than changing the reference which will change the label.
I find it a bit difficult to explain it further than that.
If you have any questions, I will try to answer them best to my knowledge
private void button1_Click(object sender, EventArgs e)
{
int numOfPeriods = Convert.ToInt32(cmbPeriods.Text)-1;
string initialString = cmbStartTime.Text; //Gets the input from combo box "cmbStartTime".
string newTime;
decimal dec = Convert.ToDecimal(TimeSpan.Parse(initialString).TotalHours); //Converts the set by user Lesson start time to a decimal value.
decimal dec2;
decimal lessonLength = 1; // Default lesson length is set to 1 hour.
TimeSpan time;
Test FormOpen = new Test();
string[] periodStartTimes = new string[9] //Loop referencing the labels on Form TEST
{
FormOpen.startTime,FormOpen.startTime2, FormOpen.startTime3, FormOpen.startTime4,
FormOpen.startTime5, FormOpen.startTime6, FormOpen.startTime7, FormOpen.startTime8,
FormOpen.startTime9
};
if (cmbLessonLength.Text != "") //If the combo box "cmbLessonLength" is not empty, use that value instead of the default lesson lenght.
{
lessonLength = Convert.ToDecimal(cmbLessonLength.Text)/60; //Converts minutes to hours.
}
dec2 = dec + lessonLength;
time = TimeSpan.FromHours(Double.Parse(dec2.ToString()));
newTime = time.ToString();
if (newTime[0] == '0')
{
FormOpen.startTime = initialString + " - " + newTime.Remove(5).Remove(0, 1);
}
else
{
FormOpen.startTime = initialString + " - " + newTime.Remove(5);
}
for (int x = 1; x <= numOfPeriods; x++) //LOOP THAT ASSIGNS VALUES TO THE ARRAY AND NOT THE REFERENCE INSIDE IT
{
decimal workingNumber = lessonLength*x;
decimal Convert0 = dec + workingNumber;
TimeSpan Convert1 = TimeSpan.FromHours(Double.Parse(Convert0.ToString()));
string Convert2 = Convert1.ToString().Remove(5);
periodStartTimes[x] = Convert2;
}
FormOpen.subjectName = cmbSubjects.Text;
FormOpen.startTime2 = periodStartTimes[1]; //IT DOES WORK LIKE THIS
FormOpen.startTime3 = periodStartTimes[2];
FormOpen.ShowDialog();
}
I have provided the whole code, so it's clearer and if there's a more efficient way of coding this I would be really thankful if someone could give me a few tips.
Your code cannot work using that array periodStartTimes This is an array of strings and when you initialize it you get the value of the property (IE the current text of the labels) not a reference to a property that you can use to change the labels.
In any case it is a bad practice to allow a different class instance change the internal values of another class. It is better to provide a public method used by the external classes to change the internal properties.
So for example your Test form class could have a public method named as SetTextLabel
public class Test : Form
{
....
public void SetLabelText(string name, string value)
{
switch(name)
{
case "startTime":
this.labelForStartTime.Text = value;
break;
case "label1":
this.firstLabelToUpdate.Text = value;
break;
...
// and so on for all other labels
}
}
}
In this way the code that changes the label is inside the Test class and you can add all the checks and validations required with full access to all the internal variables of the Test class.
Now your loop can be rewritten as
for (int x = 1; x <= numOfPeriods; x++)
{
decimal workingNumber = lessonLength*x;
decimal Convert0 = dec + workingNumber;
TimeSpan Convert1 = TimeSpan.FromHours(Double.Parse(Convert0.ToString()));
string Convert2 = Convert1.ToString().Remove(5);
FormOpen.SetLabelText("label" + x.ToString, Convert2;
}
Of course now you don't need anymore the array, and this will probably remove another error present in your actual code. The array is fixed at 9 elements but you loop for numOfPeriods starting from 1 (thus skipping the first element) and if numOfPeriods is bigger than 8 your code will crash with IndexOutOfRange exception

Counting items from a .txt file and displaying results - C#

I'm sure I'm making this much harder than it really is, but my brain hurts....
I have a program that reads a list of baseball teams from a .txt file (called Teams) and displays them into a listbox. I have another .txt file (called WorldSeries) that displays, in order, which teams have won the World Series. The WorldSeries file looks like this (minus the bullet points):
Boston Americans
New York Giants
Chicago White Sox
Chicago Cubs
Chicago Cubs
Pittsburgh Pirates
...
Meaning The Boston Americans won the first World Series, Giants second, White Sox third, etc. The dates range from 1903-2009 accordingly, however there was no World Series in 1904 or 1994.
The program allows you to select a team from the list box, click a button, and a MessageBox tells you how many times that team has won the World Series. I thought it sounded pretty easy, but I'm having a harder time than I thought I would. I think I'm doing it way wrong. Can someone please help. Thanks!
private int numberWins(int[] iArray) // Method to count total number of wins
{
int totalWins = 0; // Accumulator, intitialized to 0.
// Step through the array, adding each element to the Accumulator
for (int index = 0; index < iArray.Length; index++)
{
totalWins += iArray[index];
}
// Return the number of wins
return numberWins;
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
}
private void worldSeriesApp_Load(object sender, EventArgs e)
{
try
{
string teamName; // To hold the teams name
StreamReader inputTeams; // For file input
inputTeams = File.OpenText("Teams.txt"); // Open the file for team list
teamList.Items.Clear(); // Clear all items currently in the List Box
while (!inputTeams.EndOfStream) // While not at the end of the list of teams
{
teamName = inputTeams.ReadLine(); // Read each line
teamList.Items.Add(teamName); // Add each line to the List Box
}
inputTeams.Close(); // Close the file
}
catch (Exception ex) // Catch any errors
{
MessageBox.Show(ex.Message); // Let the user know there is an error
}
}
private void button1_Click(object sender, EventArgs e)
{
// Local variables
const int SEASONS = 104; // Number of Seasons between 1903 and 2009
int[] championships = new int [SEASONS]; // Array of seasons
StreamReader champFile; // For file input
int index = 0; // Loop counter
string selectedTeam; // Team selected from the List Box
// Open the file and get StreamReader object
champFile = File.OpenText("WorldSeries.txt");
//Read the files contents into the array
while (index < championships.Length && !champFile.EndOfStream)
{
championships[index] = int.Parse(champFile.ReadLine());
index ++;
}
if (teamList.SelectedIndex !=-1) // If a team is selected
{
//Get the selected item.
selectedTeam = teamList.SelectedItem.ToString();
// Determine if the team is in the array.
if (numberWins(champFile, selectedTeam) != 1) // If so...
{
// Display how many times that team has won the World Series
MessageBox.Show("The " + selectedTeam + "has won the World Series"
numberWins + "times!");
}
else // Otherwise..
{
// Let them know their team sucks.
MessageBox.Show("The " + selectedTeam + "sucks because they have never
won the World Series!");
}
Several problems with your code:
The statement if (numberWins(champFile, selectedTeam) != 1) is going to fail if a team won 2, 3, 4, etc. world series. This should be >= 1.
The "numberWins" function takes a list of integers, but you are calling it with two arguments, which will fail compilation.
The "numberWins" function itself doesn't make any sense, you are accumulating every value in the array, not checking for a team name at all. It should look like:
int numberWins(string teamName, string[] allChampions)
{
int numTitles = 0;
for (int i = 0; i < allChampions.Length; i++)
{
if (allChampions[i] == teamName)
numTitles++;
}
return numTitles;
}
The while loop to read the file doesn't make any sense, you are reading a list of team names into an integer array! Make championships a string array, and change your loop to:
while (index < championships.Length && !champFile.EndOfStream)
{
championships[index] = champFile.ReadLine();
index ++;
}
then call numberWins as numberWins(selectedTeam, championships);
Fixing those should get you closer. I will edit if I notice anything else.

Try block being called twice

So I have a function that retrieves data from a database, and outputs it. It's encased in a try block, so that the error from running out of rows to process is dealt with.
Here's the function that is called on load (to make the initial output), and called later on to update the log box.
Problem is, whenever I call the function again, it outputs the data twice. Since only the data is in the try block, and not the headers, this points to the try / catch being the issue.
Apologies for the messy / hacky code:
private void NavigateRecords()
{
da.Fill(ds1, "LogOutput");
textlog4.Text = "Date \t\t Time \t\t Floor\r\n";
try
{
for (int i = 0; i <= 20; i++)
{
DataRow dRow = ds1.Tables["LogOutput"].Rows[i];
for (int i2 = 1; i2 <= 3; i2++)
{
textlog4.Text += dRow.ItemArray.GetValue(i2).ToString() + "\t\t";
}
textlog4.Text += "\r\n";
}
}
catch { textlog4.Text += "----------------------"; }
}
This is the code that does part of the connecting, and may be of use:
string sql = "SELECT * From tblLog";
da = new System.Data.SqlClient.SqlDataAdapter(sql, con);
NavigateRecords();
Initial output:
Date Time Floor
6/12 18:18:22 1
----------------------
Output next time it is called:
Date Time Floor
6/12 18:18:22 1
6/12 18:46:19 2
6/12 18:18:22 1
6/12 18:46:19 2
----------------------
its not an issue with your try catch , its an issue with your variables. Clear out the variable before you add the new data to it. I do not see your variable declared in the scope of the method so it retains the data you original put in it.

Categories