C# array available outside function - c#

private void frmExecute_Load(object sender, EventArgs e)
{
string[] data = File.ReadAllLines("c:\\toyotoconsole\\tssetup.txt");
// Loop through each line, split, add if server
for (int i = 0; i < data.Length; i++)
{
var serverValues = data[i].Split('|');
}
}
Okay first C# windows project, which is cool since I have never really touched this beyond the odd debugging foray.
My problem is the array serverValues is built in a function, how do I make this array available for all functions (not sure if using the right term here) in the same form script (probably the wrong word there as well). Is there a public declaration?

Technically, you should turn local variable serverValues into a field (or property):
private string[] serverValues = new string[0];
private void frmExecute_Load(object sender, EventArgs e) {
...
serverValues = data[i].Split('|');
...
}
However, as one can see, you rewrite serverValues within the loop; that's why serverValues will contain the last line splitted only. Another issue is mixing Business logic (ServerValues) and UI (form loading).
It seems you want something like this:
using System.Linq;
...
private string[] m_ServerValues = null;
// Pure buiness logic: ServerValues without any UI (form)
public string[] ServerValues {
get {
// If we have the array we return it
if (m_ServerValues != null)
return m_ServerValues;
// otherwise we compute it
m_ServerValues = File
.ReadLines("c:\\toyotoconsole\\tssetup.txt")
.SelectMany(line => line.Split('|'))
.ToArray();
// And return it
return m_ServerValues;
}
}
// UI: form loading
private void frmExecute_Load(object sender, EventArgs e) {
// If you want to prefetch (it's not necessary)
var values = ServerValues;
}

// Declare a private property in you class
private serverValues = Array.Empty<string>();
And then use within any event
private void frmExecute_Load(object sender, EventArgs e)
{
string[] data = File.ReadAllLines("c:\\toyotoconsole\\tssetup.txt");
// Loop through each line, split, add if server
for (int i = 0; i < data.Length; i++)
{
serverValues = data[i].Split('|');
}
}

Related

I want to randomly select one of the methods I created before [duplicate]

This question already exists:
I want to randomly select one of the methods I created before when I clicked [closed]
Closed 3 years ago.
I want to randomly select one of the methods I created before when I clicked
if I can't tell you exactly what I want to say, I'm sorry for my bad English
enter code here
public void s1()
{
textBox1.Text = "ali9090";
textBox2.Text = "bar123";
}
public void s2()
{
textBox1.Text = "ali777";
textBox2.Text = "BKardak123";
}
private void button4_Click(object sender, EventArgs e)
{
Random rastgele = new Random();
rastgele.Next(s1(),s2());
}
I know my code is ridiculous, but I'd appreciate it if you told me how to do what I wanted.
You can put the methods into a collection of Action objects. Something like:
var methods = new List<Action> { () => s1(), () => s2() };
As long as your methods have the same signature, that is. (If they don't then you can wrap them in Action<> or Func<> objects that do, but the bigger question is how you plan to dynamically use methods with different signatures. So for now I'll assume they're the same.)
Then you can randomly select an element from that list like any other list and invoke it like a method:
var rastgele = new Random();
var next = rastgele.Next(methods.Count);
methods[next]();
As an aside (suggested in a comment below), it's likely that you'll want to retain the same Random instance for better randomness over time. Perhaps by placing it at the class level. Something like this:
private Random rastgele = new Random();
private void button4_Click(object sender, EventArgs e)
{
var methods = new List<Action> { () => s1(), () => s2() };
var next = rastgele.Next(methods.Count);
methods[next]();
}
The time between clicks may be making the randomness appear to work well, and for a small enough sample set it's likely to never be a problem. But it's best to get into the habit of keeping a single randomizer as it can become a source of bugs when multiple randomizers are used in rapid succession with the same seed.
The above answer is very well but if you want to implement in a simple way, you can use switch case (or if/else) like below.
private void button4_Click(object sender, EventArgs e)
{
Random rastgele = new Random();
int randomNum = rastgele.Next(1,3);
switch (randomNum)
{
case 1:
s1(); break;
case 2:
s2(); break;
}
}
Here is a solution using an Attribute to have an on-the-fly automatic management of the methods list:
using System.Reflection;
public partial class FormTest : Form
{
private List<MethodInfo> RandomMethods = new List<MethodInfo>();
private Random Random = new Random();
public FormTest()
{
InitializeComponent();
InitializeRandomMethods();
}
private void InitializeRandomMethods()
{
foreach ( var method in this.GetType().GetMethods() )
foreach ( var attribute in method.GetCustomAttributes(false) )
if ( attribute is RandomMethodAttribute )
if ( method.ReturnType != typeof(void) || method.GetParameters().Length != 0 )
{
string strError = $"Bad method signature: {GetType().Name}.{method.Name}"
+ Environment.NewLine
+ "Must have no return type and no parameters.";
MessageBox.Show(strError, Text, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
RandomMethods.Add(method);
}
[RandomMethod]
public void s1()
{
textBox1.Text = "ali9090";
textBox2.Text = "bar123";
}
[RandomMethod]
public void s2()
{
textBox1.Text = "ali777";
textBox2.Text = "BKardak123";
}
private void button4_Click(object sender, EventArgs e)
{
if (RandomMethods.Count > 0)
RandomMethods[Random.Next(RandomMethods.Count)].Invoke(this, null);
else
{
string strWarning = "No random method available.";
MessageBox.Show(strWarning, Text, MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
}
After the form class code or in another file:
public class RandomMethodAttribute : Attribute
{
public RandomMethodAttribute()
{
}
}

Cant read text file of integers into an integer array

This is driving me literally insane for some reason my code to read a simple text file of ints into an int array wont work.
private void HardButton_Click(object sender, EventArgs e)
{
int[] hard1 = { };
int counter = 0;
using (StreamReader inFile = new StreamReader("h1.txt"))
{
string str = null;
while ((str = inFile.ReadLine()) != null)
{
hard1[counter] = Convert.ToInt32(str);
counter++;
}
}
hard1 is an array of ints that i need to hold each integer placed into it by reading the text file. My error is that my array is out of bounds even though I'm iterating each time through the loop. I am at a loss.
EDIT: Here is the txt file input
0502090
6070203
0502010
5020101
0503010
4020905
0608070
7582391
6478283
8592914
5628191
6573812
4728915
3648271
C#/.Net has real arrays, not the psuedo-array collections you see in so many other languages (it has those, too, it just doesn't try to pass them off as arrays). One attribute of real arrays is a fixed size.
So when you declare the array like this:
int[] hard1 = { };
what you have is an array fixed at size 0, and therefore assigning to the array later on like this:
hard1[counter] = Convert.ToInt32(str);
is assigning to nowhere.
You have many options to fix this. Here is one of them:
private void HardButton_Click(object sender, EventArgs e)
{
var result = File.ReadLines("h1.txt").
Where(line => !string.IsNullOrWhitespace(line)).
Select(line => int.Parse(line)).
ToArray();
}
If you don't know the length in advance... use a list.
private void HardButton_Click(object sender, EventArgs e)
{
var hard1 = new List<int>();
int counter = 0;
using (StreamReader inFile = new StreamReader("h1.txt"))
{
string str = null;
while ((str = inFile.ReadLine()) != null)
{
hard1.Add(Convert.ToInt32(str));
counter++;
}
}
...
If you don't have complete control over the file it might be necessary to do extra controls before converting to int as well.
Is every line exactly one integer?
Do I need to trim?
Can there be empty lines?
Use this:
private void button1_Click(object sender, EventArgs e)
{
int[] hard1 = { };
var lines = File.ReadAllLines("h1.txt");
var lineWithoutEmptySpace = lines.Where(x => !string.IsNullOrEmpty(x)).ToArray();
hard1 = new Int32[lineWithoutEmptySpace.Length];
for (var i = 0; i < lineWithoutEmptySpace.Length; i++)
{
hard1[i] = Convert.ToInt32(lineWithoutEmptySpace[i]);
}
}

C#: ListView does not add items that come from another Class

Good day,
I'm new to whole programming thing and can't figure out / find a solution.
I've been trying to populate my ListView with Items that come from another Class.
But the ListView doesn't seem to do anything when the Class2 returns an Array.
Here is how i make it :
1 ) I search for something and send the value to Class2 ( Main Class in Form1 ):
private void tbSearch_KeyDown(object sender, KeyEventArgs e)
{
Class2 cl2 = new Class2();
if (e.KeyCode == Keys.Enter)
{
if (string.IsNullOrEmpty(tbSearch.Text))
{
MessageBox.Show("The Textbox is Empty.....");
}
else
{
listV.Items.Clear();
cl2.Search(tbSearch.Text); // Give a value to Method in Class2
}
}
}
2 ) Then in Class2 i do some internet search and return arrays with the Results :
public async void Search(string search_value)
{
/*** Read the XML Data that i've got from Response ****/
foreach (XmlNode node in XMLlist)
{
/****** Get the values that i need and write them into an array *******/
string[] result = new string[10];
result[0] = series_title;
result[1] = series_type;
result[2] = series_episodes;
result[3] = series_score;
result[4] = series_id;
result[5] = series_title_english;
result[6] = series_status;
result[7] = series_start_date;
result[8] = series_end_date;
result[9] = series_image;
Form1 fm1 = new Form1();
fm1.Update_SearchList(result); // Return an array to Form1
}
}
3) And at the end i try to populate the ListView with the returned array ( Form1 again ) :
public void Update_SearchList(string [] array)
{
ListViewItem item = new ListViewItem(array);
this.listV.BeginUpdate();
this.listV.Items.Add(item); // Here the Item.Add() Method doesn't add new Items to the ListView or they just aren't being shown.
this.listV.EndUpdate();
}
The listView.View is set to Details and the columns are being generated on Form.Load.
Is there a problem with how i execute the listView.Items.Add(); Method or is there another problem ?
When i try to do this whole operation in one single private void tbSearch_KeyDown(object sender, KeyEventArgs e) everythings works.
Thank you for your time and have a good day !
You created a new instance of Form1 in Form1 fm1 = new Form1();, which is not the instance of your caller.
I would suggest you return the result from Search() and process in Form1, or better, a callback function.
I haven't tried but a quick bypass solution could passing Form1 as a reference to the Search() function, but TBH it looks nasty to me.
private void tbSearch_KeyDown(object sender, KeyEventArgs e) {
//...
cl2.Search(tbSearch.Text, ref this); // pass the ref of current instance to cl2
}
}
}
public async void Search(string search_value, ref Form1 frm) {
//...
foreach (XmlNode node in XMLlist) {
// ...
frm.Update_SearchList(result); // use the frm reference instead
}
}
public void Update_SearchList(string [] array) {
if (InvokeRequired)
BeginInvoke(new MethodInvoker(() => Update_SearchList(array)));
else {
ListViewItem item = new ListViewItem(array);
this.listV.BeginUpdate();
this.listV.Items.Add(item);
this.listV.EndUpdate();
}
}
Note: code not tested, just a quick idea!!!
Also, I don't think if your async will work as expected if called in a non-async function.
Edit:
You can also try to return results and proceed in main form. Find the draft code as follows, but it's synced and may block your UI thread. Again, code untested!
private void tbSearch_KeyDown(object sender, KeyEventArgs e) {
//...
var results = cl2.Search(tbSearch.Text);
foreach (var item in results) Update_SearchList(item);
}
}
}
public List<xxx> Search(string search_value) {
//...
var results = new List<xxx>(); // change type to the correct type
foreach (XmlNode node in XMLlist) {
// ...
results.Add(result);
}
return results;
}

C# Filling a progressbar while a function is beeing executed

I'm currently trying to read a textfile and extract all email addresses in it. Got this working with the following function:
My C# function:
public void extractMails(string filePath)
{
List<string> mailAddressList = new List<string>();
string data = File.ReadAllText(filePath);
Regex emailRegex = new Regex(#"\w+([-+.]\w+)*#\w+([-.]\w+)*\.\w+([-.]\w+)*", RegexOptions.IgnoreCase);
MatchCollection emailMatches = emailRegex.Matches(data);
StringBuilder sb = new StringBuilder();
foreach (Match emailMatch in emailMatches)
{
sb.AppendLine(emailMatch.Value);
}
string exePath = System.Reflection.Assembly.GetEntryAssembly().Location;
string dirPath = Path.GetDirectoryName(exePath);
File.WriteAllText(dirPath + "extractedEmails.txt", sb.ToString());
}
Now I have added a progressbar, since the loaded text-file can be huge. How could I fill the progressbar while the function is beeing executed that the progressbar would be filled to 100% in the end?
I would appreciate any kind of help.
#user3185569 comment is correct. I am offering a different kind of solution without using async or await, just in case you are using an older version of Visual Studio.
Basically you need to spin your task up in a new thread, then use Invoke() to update the progress bar. Here is a simple example:
private int _progress;
private delegate void Delegate();
private void btnStartTask_Click(object sender, EventArgs e)
{
// Initialize progress bar to 0 and task a new task
_progress = 0;
progressBar1.Value = 0;
Task.Factory.StartNew(DoTask);
}
private void DoTask()
{
// Simulate a long 5 second task
// Obviously you'll replace this with your own task
for (int i = 0; i < 5; i++)
{
System.Threading.Thread.Sleep(1000);
_progress = (i + 1)*20;
if (progressBar1.InvokeRequired)
{
var myDelegate = new Delegate(UpdateProgressBar);
progressBar1.Invoke(myDelegate);
}
else
{
UpdateProgressBar();
}
}
}
private void UpdateProgressBar()
{
progressBar1.Value = _progress;
}
You just iterate through all the objects in the file that you want. You need the amount of objects in there,then you multiply the current iterator by 100 divided by the total amount of objects. Theres your persentage. Now update the process of the bar with the value you got.

Display strings from a list one by one into a label

I have a label. I have a list. when I do "label1.Text = match.Value;", it just displays the last item of the list, as opposed to 1 string that changes each time I click a button. The code is:
private void frontPageToolStripMenuItem_Click(object sender, EventArgs e)
{
const string url = "http://reddit.com/r/pics";
var source = getSource(url);
var regex = new Regex([regex removed]);
var links = new List<string>();
var titles = new List<string>();
foreach (Match match in regex.Matches(source))
{
links.Add(match.Groups[1].Value);
titles.Add(match.Groups[2].Value);
}
foreach (var title in titles)
{
label1.Text = title; /*it just shows the last 'title' in 'titles', I want it to start at the first, and go to the next title every time the event occurs (frontPageToolStripMenuItem_Click)*/
}
}
Thanks in advance!
You need to initialize the list outside of your click event handler. You could create an FetchImageData method that is called when your program starts (perhaps call it from the constructor of your class). Or you could call it the list the first time the click event is fired.
private int clickCounter = 0;
private List<string> links;
private List<string> titles;
private void FetchImageData()
{
links = new List<string>();
titles = new List<string>();
const string url = "http://reddit.com/r/pics";
var source = getSource(url);
var regex = new Regex([regex removed]);
foreach (Match match in regex.Matches(source))
{
links.Add(match.Groups[1].Value);
titles.Add(match.Groups[2].Value);
}
}
You haven't said what should happen when the user clicks more times than there are elements. One option is to wrap around and starts again from the beginning. This can be achieved using the % operator.
private void frontPageToolStripMenuItem_Click(object sender, EventArgs e)
{
if (titles == null) { FetchImageData(); }
label1.Text = titles[clickCounter % titles.Count];
clickCounter++;
}
UI thread doesn't get a chance to update the label because your for loop is on the UI thread. Even if you move the for loop to a background thread good chance you 'll only see some flickering and then the final string. Just append the strings to a textbox or output them using Debug.writeLine. This will show you that you are reading the correct strings.
To change the label just once don't do it in a for loop
1) titles should be global variable
2) Move this in the constructor of the form
const string url = "http://reddit.com/r/pics";
var source = getSource(url);
var regex = new Regex("<a class=\"title \" href=\"(.*?)\" >(.*?)<");
titles = new List<string>();
foreach (Match match in regex.Matches(source))
{
links.Add(match.Groups[1].Value);
titles.Add(match.Groups[2].Value);
}
label1.Text = first value of the titles
3) Your event handler should be like this:
private void frontPageToolStripMenuItem_Click(object sender, EventArgs e)
{
label1.Text = next value of the titles variable;
}
In Second foreach loop put label1.Text += title; instead of label1.Text = title; then it will work fine.

Categories