Calculating average with SelectedIndices - c#

My program reads coordinates(double x,douule y) into ListBox and need to calculate the average of them after choosing them with SelectedIndices and MultiExtended.
The problem is how can I refresh my code with each Multiselection.
As you can see I set SelectedIndices[0] to 0 as default. At the moment my program just making average of the 1st coordinate divided by number of selectedIndices.
If you think about any ways to improve my code I would like to know as well.
Thanks!
private void button3_Click(object sender, EventArgs e)//Average
{
int[] selected = new int[] {points_List.SelectedIndices[0] };
double sumX = 0, sumY = 0; ;
foreach (int iIndex in selected)
{
sumX += points[iIndex].X;
sumY += points[iIndex].Y;
}
averageX = (sumX) / (points_List.SelectedIndices.Count);
averageY = (sumY) / (points_List.SelectedIndices.Count);
label1.Text = "Average is: ";
label1.Text += averageX.ToString();
label1.Text += " ";
label1.Text += averageY.ToString();
}

The correct code will require a cast of SelectedIndices through OfType<T> or Cast<T>. Also, it's convenient to call ToArray to materialize the result to avoid having to compute it twice.
var selectedPoints = points_List.SelectedIndices.
OfType<int>().
Select(i => points[i]).
ToArray();
var averageX = selectedPoints.Average(p => p.X);
var averageY = selectedPoints.Average(p => p.Y);

Final solution, Thanks all.
{
double averageX = 0, averageY = 0;
var selectedPoints = from int i in pointsList.SelectedIndices select points[i];
if (pointsList.SelectedIndices.Count == 0)
{
label1.Text = "Average is 0.000 0.000 ";//default text
return;
}
averageX = selectedPoints.Average(p => p.X);
averageY = selectedPoints.Average(p => p.Y);
label1.Text = "Average X: ";
label1.Text += averageX.ToString();
label1.Text += " Y:";
label1.Text += averageY.ToString();
}

Related

How to use a foreach loop to generate a textbox to show a list of questions in C# Windows Forms

I'm new to windows forms.
My program is to show random questions for the user to answer and I want when the user press the end button to show the questions and the user answers and the right answer should my question and answers be in var?
I created a string list and can't seem to figure it out.
namespace WindowsFormsApplication7
{
public partial class Form1 : Form
{
int numofquestionleft;
int answer;
int useranswer33;
Timer Clock = new Timer();
List<string> questions = new List<string>();
List<string> answers = new List<string>();
List<string> useranswers= new List<string>();
public Form1(){
}
int[] Rand(int v)
{//random number generater
Random r = new Random();
int a = r.Next(1,v);
int b = r.Next(1,v);
int[] N = {Math.Max(a,b) , Math.Min(a,b)};
return N;
}
void generate()
{
//user choosing the range of numbers that is used in questions
int range = 0;
switch (rangebox1.SelectedIndex)
{
case 0:
range = 100;
break;
case 1:
range = 500;
break;
case 2:
range = 1000;
break;
default:
MessageBox.Show("Put a range !");
break;
}
int[] numbers = Rand(range);
switch (Operationbox1.SelectedIndex)
{
case 0:
questionlbl1.Text = string.Format("{0} + {1} =",numbers[0],numbers[1]);
answer = numbers[0] + numbers[1];
answers.Add(answer.ToString());
break;
case 1:
questionlbl1.Text = string.Format("{0} - {1} =" , numbers[0], numbers[1]);
answer = numbers[0] - numbers[1];
answers.Add(answer.ToString());
break;
case 2:
questionlbl1.Text = string.Format("{0} * {1} =" , numbers[0], numbers[1]);
answer = numbers[0] * numbers[1];
answers.Add(answer.ToString());
break;
case 3:
questionlbl1.Text = string.Format("{0} / {1} =" , numbers[0], numbers[1]);
answer = numbers[0] / numbers[1];
answers.Add(answer.ToString());
break;
default:
MessageBox.Show("Please insert a operation");
break;
}
\
}
void numberquest()
{//if the number of question left is more than 0 genrate and minues 1 question
if (numofquestionleft > 0)
{
generate();
}
else
{
MessageBox.Show("End of questions, Please press END");
}
numofquestionleft--;
numberofquestionnumber.Text = "Questions left " + numofquestionleft;
}
private void genbutton1_Click(object sender, EventArgs e)
{ //Button that start the timer and generate the question
numofquestionleft = Convert.ToInt32(numofquest1.Text);
generate();
}
private void end22_Click(object sender, EventArgs e)
{
foreach (var questionlist in question)
{
// here is my problem what should I put here to display the question list
}
}
private void button2_Click(object sender, EventArgs e)
{//button that checks if the useranswer is right or wrong
useranswer33 = Convert.ToInt32(useranswerbox1.Text);
useranswers.Add(answer.ToString());
if (useranswer33 == answer)
{
result.Text = "Your answer is correct";
}
else
{
result.Text = "Your answer is Wrong, The correct answer;
}
}
}
}
You can do such thing to dynamically generate controls to create your quiz:
var questions = new string[]
{
"This is the question 1",
"This is the question 2",
"This is the question 3",
"This is the question 4"
}
int x = 50;
int y = 10;
int dy = 30;
int width = 250;
foreach ( var question in questions )
{
var textbox = new TextBox();
textbox.Text = question;
textbox.Width = width;
textbox.Location = new Point(x, y);
Controls.Add(textbox);
y += dy;
}
You can adapt for what you want by changing and adding controls for you need: type of controls, appearance, locations, sizes, content, and so on.
Here controls are added to the form itself but you can put them in a panel or any container:
SomePanel.Controls.Add(textbox);
Hence you can create questions with labels and add a textbox or radioboxes for answers and name them. You can also keep controls created to get answers later:
var texboxesAnswers = new List<TextBox>()
int index = 0;
// ...
foreach ( var question in questions )
{
var label = new Label();
label.Text = question;
label.AutoSize = true;
label.Location = new Point(x, y);
PanelQuestions.Controls.Add(label);
y += dy;
var textbox = new TextBox();
textbox.Text = "";
textbox.Width = width;
textbox.Location = new Point(x, y);
textbox.Name = "TextBoxAnswer" + (index++);
PanelQuestions.Controls.Add(textbox);
texboxesAnswers.Add(textbox);
y += dy + dy / 2;
}
Without using textboxesAnswers you can get all answers like that:
using System.Linq;
var textboxesAnswers = PanelQuestions.Controls
.OfType<TextBox>()
.Where(n => n.Name.StartsWith("TextBoxAnswer"));

Calculated Progress percentage not updating

I'm trying to show the percent value of progression With a background worker in a Label .Im Adding Aprox. 25 K rows to a DataTable. It work fine when I set Label.Text to e.ProgressPercentage only . But when I calculate the % value, it remains same.Only after completion of the worker The label updates to 100%
progressCount = report.Rows.Count;
foreach (DataRow r in report.Rows)
{
rp.pName = r[1].ToString();
rp.batch = r[2].ToString();
rp.expr = r[3].ToString();
rp.stock = r[5].ToString();
rp.rate = r[6].ToString();
backgroundWorker2.ReportProgress(i, rp);
System.Threading.Thread.Sleep(2);
if(backgroundWorker2.CancellationPending)
{
e.Cancel = true;
backgroundWorker2.ReportProgress(0);
}
i++;
}
private void backgroundWorker2_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
metroProgressBar1.Minimum = 0;
metroProgressBar1.Maximum = progressCount;
stock st = new stock();
reportClass rp = (reportClass)e.UserState;
if(!backgroundWorker2.CancellationPending)
{
st.stockReport.Rows.Add(rp.pName, rp.batch, rp.expr, rp.stock, rp.rate);
metroProgressBar1.Value = e.ProgressPercentage;
int percn = (e.ProgressPercentage / progressCount) * 100;
metroLabel4.Text =percn.ToString();
}
}
You're most likely dividing an integer by an integer, which results in zero. Cast your values to double first, do the calculation, then cast the result back to an int.
Change:
int percn = (e.ProgressPercentage / progressCount) * 100;
To:
int percn = (int)(((double)e.ProgressPercentage / (double)progressCount) * 100);

How to convert Listview dates to local time zone?

I have 3 columns in the ListView. From,Subject,Date
I'm using the OpenPop library.
private int numberofallmessages = 0;
private int countMsg = 0;
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
OpenPop.Pop3.Pop3Client PopClient = new OpenPop.Pop3.Pop3Client();
PopClient.Connect("mail", 110, false);
PopClient.Authenticate("me", "me",
OpenPop.Pop3.AuthenticationMethod.UsernameAndPassword);
List<string> uids = PopClient.GetMessageUids();
int messageCount = PopClient.GetMessageCount() -1;
numberofallmessages = messageCount;
allMessages = new List<OpenPop.Mime.Message>(messageCount);
for (int i = messageCount; i > 0; i--)//for (int i = messageCount - 1; i > -1; i--)
{
if (backgroundWorker1.CancellationPending == true)
{
e.Cancel = true;
return;
}
string currentUidOnServer = uids[i];
if (!seenUids.Contains(currentUidOnServer))
{
if (i > 0)
allMessages.Add(PopClient.GetMessage(i));
SaveFullMessage(PopClient.GetMessage(i), i);
w = new StreamWriter(emailsIDSFile, true);
w.WriteLine(currentUidOnServer);
w.Close();
int nProgress = (messageCount - i + 1) * 100 / messageCount;
backgroundWorker1.ReportProgress(nProgress, PopClient.GetMessageCount().ToString() + "/" + i);
}
}
PopClient.Disconnect();
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pbt.Value = e.ProgressPercentage;
pbt.Text = e.ProgressPercentage.ToString() + "%";
pbt.Invalidate();
label8.Text = e.UserState.ToString();
label8.Visible = true;
lvnf.Items.Add(new ListViewItem(new string[]
{
allMessages[countMsg].Headers.From.ToString(), //From Column
allMessages[countMsg].Headers.Subject, //Subject Column
allMessages[countMsg].Headers.DateSent.ToString() //Date Column
}));
countMsg += 1;
}
The problem is in the progresschanged event i think. Where i add the items to each column.
When it's adding the emails to the ListView i see it like this:
The problem is on the date column the date is fine but the time in not my time. Not sure of what place the time is but in my place it's now 1:52 AM
How can i get/set the time of my place ?
I couldn't find in the line:
allMessages[countMsg].Headers.DateSent.ToString()
How to change it to my time.
Try this:
allMessages[countMsg].Headers.DateSent.ToLocalTime().ToString();
You want to utilize the DateTime.ToLocalTime() method. It does the heavy lifting for you.
Hope this helps
Edit: Removed incorrect version as the documentation for OpenPop.Net states that the MessageHeader.DateSent property is in fact a DateTime object.

Adding a linked label for a list of features

I have a class that contains a list of features and I would like to add a link label for each item in that list. When doing this, I am not able to display all of the features, only the first feature. The smallest code snippet I have is:
foreach (var element in agol.orgServices.services)
{
var linkLabel = new LinkLabel();
linkLabel.Text = element.name + "\n";
linkLabel.Links.Add(new LinkLabel.Link(i, element.url.Length, element.url));
i = linkLabel.Text.Length;
ServicesTab.Controls.Add(linkLabel);
linkLabel.LinkClicked += (s, z) =>
{
System.Diagnostics.Process.Start(z.Link.LinkData.ToString());
};
}
The results I get are:
What I expect to get is something similar to this:
The second image is not individual labels added but a long text string instead. See code snippet below.
finalstring += element.name + "\n"
What am I doing wrong?
I solved it. The link labels were stacking on top of each other so I had to include an increment:
int i=0;
int yi = 30;
int y = 7;
int x = 2;
foreach (var element in agol.orgServices.services)
{
var linkLabel = new LinkLabel();
linkLabel.Name = element.name;
linkLabel.Text = element.name + "\n";
linkLabel.Location = new Point(x, y);
linkLabel.AutoSize = true;
linkLabel.Links.Add(new LinkLabel.Link(i, element.name.Length, element.url));
ServicesTab.Controls.Add(linkLabel);
linkLabel.LinkClicked += (s, z) =>
{
System.Diagnostics.Process.Start(z.Link.LinkData.ToString());
};
y += yi;
//finalServiceList += element.name + "\n";
}

How to display array elements, if the number of elements is a variable

I'm making a calculator in GUI, and I need some help.
When I enter some data in a text box, I need to store it in an array. This is how I thought of it.
int numOfPackages;//used to get user input
private void button3_Click(object sender, EventArgs e)
{
int[] weight = new int[numOfPackages];
for(int i = 0; i < numOfPackages; i++)
{
weight[i] = Convert.ToInt32(weightBox.Text);
}
foreach (int i in weight)
totalCostLabel.Text = "" + weight[i];
}
And when I try to display the elements, it gives me the indexOutOfRange exception.
So, how do I display the elements of that array?
Thanks in advance.
This line
foreach (int i in weight)
totalCostLabel.Text = "" + weight[i];
should be
foreach (int w in weight)
totalCostLabel.Text = "" + w;
Your current code iterates the array of weights, and tries to use the weight as an index into the array of weights, causing an index out of range exception.
Another problem is with the first loop: you are setting all values of weight to the same number:
weight[i] = Convert.ToInt32(weightBox.Text); // That's the same for all i-s
If weights are to be different, they should come from different weight boxes, or the string from a single weightBox should be processed in such a way as to produce multiple numbers (for example, by using string.Split).
You have multiple problems here. First is this:
foreach (int i in weight)
totalCostLabel.Text = "" + weight[i];
This is iterating the weight array and using each value in that array. You then use that value as an index. Take the following example:
weight[0] = 0
weight[1] = 1
weight[2] = 15
In your code, the first two entries will work because there is an index of 0 and an index of 1. But when it gets to the last entry, it looks for an index of 15. You can fix this two ways, the first is to use a regular for loop:
for(int i=0; i < weight.Length; i++)
{
totalCostLabel.Text += weight[i];
}
This brings the second mistake. You aren't appending anything to your totalCostLabel in your code, you are just replacing the value. This will append all the values of weight together as one.
Another way to do this is to use the foreach loop:
foreach(int i in weight)
{
totalCostLabel.Text += i;
}
This is the same as above but you don't have to worry about indexing.
Bottom line, even after you fix your loop, you will probably need to fix the way that the label takes the text otherwise you won't get your desired result.
Maybe you wanted something more like?
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
btnAdd.Enabled = false;
}
int[] weight;
int entriesMade;
int numOfPackages;
private void btnReset_Click(object sender, EventArgs e)
{
if (int.TryParse(numEntriesBox.Text, out numOfPackages))
{
weight = new int[numOfPackages];
entriesMade = 0;
btnReset.Enabled = false;
btnAdd.Enabled = true;
totalCostLabel.Text = "";
}
else
{
MessageBox.Show("Invalid Number of Entries");
}
}
private void btnAdd_Click(object sender, EventArgs e)
{
int value;
if (int.TryParse(weightBox.Text, out value))
{
weight[entriesMade] = value;
weightBox.Clear();
totalCostLabel.Text = "";
int total = 0;
for (int i = 0; i <= entriesMade; i++)
{
total = total + weight[i];
if (i == 0)
{
totalCostLabel.Text = weight[i].ToString();
}
else
{
totalCostLabel.Text += " + " + weight[i].ToString();
}
}
totalCostLabel.Text += " = " + total.ToString();
entriesMade++;
if (entriesMade == numOfPackages)
{
btnAdd.Enabled = false;
btnReset.Enabled = true;
MessageBox.Show("Done!");
}
}
else
{
MessageBox.Show("Invalid Weight");
}
}
}

Categories

Resources