I created a dynamic UI that shows each module that the user has added to their selection and all the assessments for that module underneath the module name,
All data is saved in array lists - including objects as textBoxes and labels.
Here's what it looks like:
http://www.4shared.com/photo/fullsize/Ja3jHpRJ/screen1.html
Then the user should enter their marks for each assessments
And the Calculate button should calculate their overall mark for each module
At this stage I am just adding the marks together.
The program works fine when there's only one module added, but when there are more modules it seems to think that a TextBox is empty, even though i fill them all with numbers.
here is my code
private void calculateButton_Click(object sender, EventArgs e)
{
int modLength = dat.ModuleTitle.Count;
int modAsses = 0;
int loopCount = 0;
for (int i = 0; i < modLength; i++)
{
int total = 0;
if ((textboxComputer[loopCount] as TextBox).Text == "")
{
Console.WriteLine("!!!!!");
}
else
{
modAsses = int.Parse(dat.ModuleAssessNum[i].ToString());
for (int y = 0; y < modAsses; y++)
{
total = total + int.Parse((textboxComputer[loopCount] as TextBox).Text.ToString());
loopCount = loopCount + 1;
}
Console.WriteLine(total);
}
}
}
When i add two or more modules it displays the "!!!!!" message, but calculates the mark for the first module added.
here's some output
http://www.4shared.com/photo/fullsize/PlY29BMQ/screen2.html
You need to make sure that the code that creates the extra dynamic elements on screen is being called as part of the page load, so that then the viewstate is inserted back into the elements and can be read back out by your code.
there is something wrong with your code, probably a lot wrong(except the names of your variables).
Take a look at your loopCount variable - you will only conditionally change it in your loop but you always use it at the start of the loop(where you do textboxComputer[loopCount]).
So what's the expected behavior of that? The first time you get in to the loop if you go to your 'else' part you may print the total as you say but you also change the loopCount variable, once you get to the Console.WriteLine("!!!!!"); you never change it again - so your iterations will behave the same.
Related
I've been working on a project where I need on a button press that this line gets executed.
if (listView1.SelectedItems[0].SubItems[3].Text == "0") //Checks to see Value
{
listView1.SelectedItems[0].SubItems[3].Text = "1";// If Value is Greater, Increase and Change ListView
questionNumberLabel.Text = listView1.SelectedItems[0].SubItems[3].Text;// Increase and Change Label
}
Now I have this repeated about 10 times with each value increasing by one. But I know that this is ugly, and dysfunctional. As well as conflates the file size. I've tried a few things. Primarily this method.
if (listView1.SelectedItems[0].SubItems[3].Text == "0")
{
for (var i = 1; i < 100;)
{
if (!Int32.TryParse(listView1.SelectedItems[0].SubItems[3].Text, out i))
{
i = 0;
}
i++;
listView1.SelectedItems[0].SubItems[3].Text = i.ToString();
Console.WriteLine(i);
}
}
But instead of just adding one, it does the 100 instances and ends. The reason this is becoming a pain in the *** is because the
listView1.SelectedItems[0].SubItems[3].Text
is just that - it's a string, not an int. That's why I parsed it and tried to run it like that. But it still isn't having the out come I want.
I've also tried this
string listViewItemToChange = listView1.SelectedItems[0].SubItems[3].Text;
Then parsing the string, to make it prettier. It worked like it did before, but still hasn't given me the outcome I want. Which to reiterate is, I'm wanting the String taken from the list view to be changed into an int, used in the for loop, add 1, then restring it and output it on my listView.
Please help :(
You say you want the text from a listview subitem converted to an int which is then used in a loop
so - first your creating your loop variable, i, then in your loop you're assigning to it potentially 3 different values 2 of which are negated by the, i++. None of it makes sense and you shouldn't be manipulating your loop variable like that (unless understand what you're doing).
if you move statements around a little..
int itemsToCheck = 10; // "Now I have this repeated about 10 times "
for (var item = 0; item < itemsToCheck; item++)
{
int i;
if (!Int32.TryParse(listView1.SelectedItems[item].SubItems[3].Text, out i))
{
i = 0;
}
i++;
listView1.SelectedItems[item].SubItems[3].Text = i.ToString();
Console.WriteLine(i);
}
Something along those lines is what you're looking for. I haven't changed what your code does with i, just added a loop count itemsToCheck and used a different loop variable so your loop variable and parsed value are not one in the same which will likely be buggy.
Maybe this give you an idea. You can start using this syntax from C# 7.0
var s = listView1.SelectedItems[0].SubItems[3].Text;
var isNumeric = int.TryParse(s, out int n);
if(isNumeric is true && n > 0){
questionNumberLabel.Text = s;
}
to shortcut more
var s = listView1.SelectedItems[0].SubItems[3].Text;
if(int.TryParse(s, out int n) && n > 0){
questionNumberLabel.Text = s;
}
So I'm working in Visual Studio 2015 with a few custom classes. One of which is called MinPriorityQueue, and it is a priority queue that, in this situation, allows me to retrieve the object of MinimumPriority in the queue via a property MinimumPriority. There is also a method called RemoveMinimumPriority, which is self-explanatory.
I am not allowed to modify this method, it was pre-made for us for this assignment, otherwise I would have already found a simple solution.
My program is meant to compare two text files, and return a value based off a certain equation which isn't important as far as this post goes. The problem I am having is within my UserInterface code. Here is my click event for the 'Analyze' button on my GUI.
private void uxAnalyze_Click(object sender, EventArgs e)
{
Dictionary<string, StoreWord> dictionary = new Dictionary<string, StoreWord>();
const int _numFiles = 2;
MinPriorityQueue<float, StoreInfo> minQueue = new MinPriorityQueue<float, StoreInfo>();
int numWords1 = 0;
int numWords2 = 0;
//Process Both Input Files
using (StreamReader sr = new StreamReader(uxTextBox1.Text))
{
for (int i = 0; i < _numFiles; i++)
{
if (i == 0)
{
dictionary = ReadFile(dictionary, uxTextBox1.Text, i, out numWords1);
}
if (i == 1)
{
dictionary = ReadFile(dictionary, uxTextBox2.Text, i, out numWords2);
}
}
}
int[] numWords = new int[2];
numWords[0] = numWords1;
numWords[1] = numWords2;
//Get 50 Words with Highest Combined Frequencies
foreach(var entry in dictionary.Values)
{
StoreInfo freq = new StoreInfo(entry, numWords);
minQueue.Add(freq, Convert.ToSingle(entry[0] + entry[1]));
if(minQueue.Count > 50)
{
minQueue.RemoveMinimumPriority();
}
}
//Compute and Display the Difference Measure
float diffMeasure = 0;
float temp = 0;
foreach( x in minQueue)
for (int i = 0; i < minQueue.Count; i++)
{
temp += minQueue.????; //This is where my problem stems
}
diffMeasure = (float)(100 * Math.Sqrt(temp));
}
A few lines from the end you will see a comment showing where my problem is located. The MinPriorityQueue (minQueue) has two parameters, a Priority, and a Value, where the Priority is a Float, and the Value is another class called StoreInfo. This class has an Indexer, which will return information from a different file depending on what the index is. In this case, there are only two files. For example: StoreInfo[i] returns the frequency of a word in the ith text file.
Ideally, my code would look like this:
for (int i = 0; i < minQueue.Count; i++)
{
temp += (minQueue.minimumValue[0] - minQueue.minimumValue[1])*(minQueue.minimumValue[0] - minQueue.minimumValue[1]);
}
diffMeasure = (float)(100 * Math.Sqrt(temp));
Problem is, that would require a minimumValue property, which I don't have access to. All I have is minimumPriority.
As far as I can see, there is no other way for me to get the Values that I need in order to get the frequencies that I need to get from the indexer and put into the equation.
Help is much appreciated.
Alright guys, I've been thinking at this for far too long, and it doesn't seem like anyone else sees another solution either.
At this point, I'm just going to go with the logical solution and add another property into the MinPriorityQueue class, even though it is against my professor's wishes.
Thank you all anyway.
I have a method in a windows form application that tries to remove 2 text boxes from a panel.
In the method, I loop through all the controls in the panel. There are always supposed to be 2 panels removed and added together, but when removing, it randomly removes 1 or 2 containers when I press the button.
Here is the code to remove the textboxes:
private void removeRows()
{
string descName = "Desc" + (textBoxCounter - 1).ToString();
string costName = "Cost" + (textBoxCounter - 1).ToString();
if (textBoxCounter >= 0)
{
foreach (Control c in costItems.Controls)
{
if (c.Name == descName)
{
// Remove the control from the panel and dispose of it
panel.Controls.Remove(c);
c.Dispose();
}
if(c.Name == costName)
{
// Remove the control from the panel and dispose of it
panel.Controls.Remove(c);
c.Dispose();
}
}
// Decrement the counter
// This happens only once since two controls need to be removed
if (textBoxCounter == 0)
textBoxCounter = 0;
else
textBoxCounter--;
}
else
MessageBox.Show("There are no more rows to remove", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
testlabel1.Text = textBoxCounter.ToString();
testlabel2.Text = panel.Controls.Count.ToString();
}
Here is the code to add a button:
private void addRows(string desc, string cost)
{
if (textBoxCounter >= maxExpenses)
{
MessageBox.Show("Maximum number of expenses entered", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
TextBox Desc = new TextBox();
TextBox Cost = new TextBox();
// Give the text boxes names
Desc.Name = "Desc" + textBoxCounter.ToString();
Cost.Name = "Cost" + textBoxCounter.ToString();
// Format the text boxes
Desc.Width = panel.Width / 2;
Cost.Width = panel.Width / 4;
// Add the items to the costItems panel
panel.Controls.Add(expenseDesc);
panel.Controls.Add(expenseCost);
// Add the items to the expenses dictionary
panel.Add(Desc, Cost);
// Increment the text box counter variable
textBoxCounter++;
testlabel1.Text = textBoxCounter.ToString();
testlabel2.Text = costItems.Controls.Count.ToString();
}
}
Some info to know.
There will always be 2 textboxes added and removed, they relate to each other.
The textBoxCounter is initialized to 0, so the first two boxe names will be "Desc0" and "Cost0".
When I press the button to remove rows the first time, one text box is removed, and then if i press it again it might remove 2, it might only remove 1.
I tried debugging and I noticed that the foreach loop that iterates over all the controls in the panel seems to loop one time short of the full number of controls.
Any help with my code would be great.
Your problem is caused by the foreach, modifying the collection in foreach may cause some unexpected behavior. You just want to remove the TextBoxes with names being known beforehand, so why not using the method ControlCollection.RemoveByKey?
If you want to remove the last added textBoxes (Desc... and Cost...) do this:
panel.Controls.RemoveByKey(descName);
panel.Controls.RemoveByKey(costName);
If you want to remove all the added textBoxes (suppose you have other kinds of TextBoxes, otherwise we can use a little LINQ to remove all the textboxes easily):
for(int i = 0; i < textBoxCounter; i++){
panel.Controls.RemoveByKey("Desc" + i);
panel.Controls.RemoveByKey("Cost" + i);
}
Your code has two problems: you are disposing something you cannot dispose and you are iterating through a collection (which you are modifying) in the wrong way. You can delete all the Controls by doing:
panel.Controls.Clear();
Or iterating backwards by relying on the indices:
for (int i = panel.Controls.Count - 1; i >= 0; i--)
{
panel.Controls.RemoveAt(i);
}
Regarding the Dispose, you can use it if you wish but don't need to use Remove:
for (int i = panel.Controls.Count - 1; i >= 0; i--)
{
panel.Controls[i].Dispose();
}
PS: I asked something identical to this and got -6. One of the reasons for maintaining this question was precisely being helpful to others (I saw the code you are using to delete controls in internet and I knew that quite a few people were using it). Pretty ironical, indeed.
problem solved
I am working on a project where an array holds the scores of 5 tests, but the user does not have to fill the array with 5 scores total. there is a button that displays a message box that lists the 5 scores values. The user needs to be able to run the program twice in a row without restarting the program, every time the 2nd round comes around, the array is still holding the last rounds values. I can't set the values to zero, because a live average is calculated and displayed after each score is entered, and the zeros throw off the average.
This is the button that displays the scores. If the user enters fewer than 5 scores (5 is size of array) the message box should display only those 4 or less scores, the way I have it now, it is displaying zeroes for the unused values.
private void btnDisplayScores_Click(object sender, EventArgs e)
{
for (int x = 0; x < counter; x++)
{
Convert.ToString(scoreArray[x]);
}
MessageBox.Show(scoreArray[0] + Environment.NewLine
+ scoreArray[1] + Environment.NewLine + scoreArray[2]
+ Environment.NewLine+ scoreArray[3] + Environment.NewLine
+ scoreArray[4]);
We have only learned to use null with strings, we have not gotten into nullable integers and decimals. We are expected to do it without using a nullable numerical type.
This resets the values so the user can start another round.
private void Restart()
{
scoreTotal = 0;
txtScore.Clear();
txtScoreTotal.Clear();
txtScoreCount.Clear();
txtAverage.Clear();
for (int x = 0; x <= counter; x++)
{
scoreArray[x] = 0;
}
counter = 0;
}
And maybe this will help.
private void btnAdd_Click(object sender, EventArgs e)
{
int currentScore;
if (counter < 5)
{
if (DataValid() && DataRange())
{
currentScore = Convert.ToInt32(txtScore.Text);
Input(currentScore);
Process();
}
else
{
MessageBox.Show("Data was invalid, please enter valid data.", "Error");
}
counter++;
}
else
{
Restart();
}
txtScore.Focus();
}
edit* i mistakenly thought i needed to convert the array to string to display it in the message box, fixed that but its not at the core of my problem.
i may try to the -1 suggestion tonite or tommarow
havnt learned list yet, array is declared global
edit2* problem solved, used the -1 solution, thanks to mfussenegger
I'm a C# newbie and I'm really confused about something I'm trying to do for a project in a C# class.
The assignment is some list manipulation in C#.
The program accepts a list of items in the text box, then iterates through those items, creating multiple copies of the list. It randomly resizes each copy of the list to between 3 and all items. It then outputs all the copies.
The problem I'm having is that when I step through this program with the debugger, I get the expected output. The same happens if I display a message box after each iteration (as I have in the code below).
However, if I just run the program straight through, I get a different output. Instead of variations in the lists, all the copies of the list are exactly the same.
If you see in the code I've commented "// FIRST DEBUG MESSAGEBOX" and "// SECOND DEBUG MESSAGEBOX". If the first debug messagebox code is left in there, the output is as expected...multiple versions of the list are output with random lengths between 3 and all items.
However, and this is where I'm confused...if you comment out the first debug messagebox code, you get a different result. All versions of the list output are the same length with no variation.
Any help would be appreciated! Here's the code I have so far...sorry if it's terrible - I'm new at C#:
public partial class MainForm : Form
{
/**
* Vars to hold raw text list items
* and list items split by line
*/
String rawListItems = "";
List<string> listItems = new List<string>();
List<List<string>> textListItems = new List<List<string>>();
public MainForm()
{
InitializeComponent();
}
private void cmdGo_Click(object sender, EventArgs e)
{
// store the contents of the list item text box
this.rawListItems = txtListItems.Text;
this.listItems.AddRange(Regex.Split(this.rawListItems, "\r\n"));
// setup min and max items - max items all items
int minItems = 3;
int maxItems = this.listItems.Count;
// We'll copy this list X times, X = same number of items in list
for (int i = 0; i < this.listItems.Count; i++)
{
// make a copy of the list items
List<string> listItemsCopy = new List<string>(this.listItems);
// get a random number between min items and max items
Random random = new Random();
int maxIndex = random.Next(minItems, maxItems + 1); // max is exclusive, hence the +1
// remove all elements after the maxIndex
for (int j = 0; j < listItemsCopy.Count; j++)
{
if (j > maxIndex)
{
listItemsCopy.RemoveAt(j);
}
}
// add the list copy to the master list
this.textListItems.Add(listItemsCopy);
// FIRST DEBUG MESSAGEBOX
String tst = "";
foreach (string item in listItemsCopy)
{
tst += item + " ## ";
}
MessageBox.Show(tst);
}
// SECOND DEBUG MESSAGEBOX
String output = "";
foreach (List<string> listitem in this.textListItems)
{
foreach (string item in listitem)
{
output += item + " ## ";
}
}
MessageBox.Show(output);
}
}
Move the creation of Random out of the loop:
Random random = new Random();
By default, the constructor uses a default time based seed. In a tight loop, you may be getting 'the same' random generator instead of a different one with each loop.
When using MessageBoxes or single stepping, you are allowing the timer to run and getting 'a new' random generator in each loop.
I don't understand your assignment exactly, but this loop seems to be incorrect:
for (int j = 0; j < listItemsCopy.Count; j++)
{
if (j > maxIndex)
{
listItemsCopy.RemoveAt(j);
}
}
when you remove an element in the middle of a list, elements after that get shifted, so not all the elements after maxIndex get removed, as you might expect.
In circumstances where stepping through the code in a debugger affects the behaviour of the program, a useful alternative debugging technique is to use the System.Diagnostics namespace in particular the Trace class.
The Trace functions work much like Console.WriteLine(), you can trace a string or a format string plus an array of objects to populate the format string, e.g.:
Trace.TraceInformation("some message that tells me something");
Trace.TraceInformation("some useful format string {1}, {0}",
new object[] {someObject, someOtherObject});