using a list across different methods in c# - c#

I am reading a file into a list and then want a button to pull a random entry from the list. I can do this in VB but am fairly new to c#. I know I have to make the list public, but I'm getting increasingly frustrated.
The code below reads the file to a list and then a listbox.
namespace texttoarray
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
int counter = 0;
string line;
var list = new List<string>();
var file = new StreamReader(#"list.txt");
while ((line = file.ReadLine()) != null)
{
list.Add(line);
counter++;
}
listBox2.DataSource = list;
var rnd = new Random();
}
}
}

If you want to process some information inside one method and use this processed information inside another method, you can:
pass the information as an argument to the second method
keep the information inside your class and use it inside any method
I'll assume the second approach for you, so you can do something like this:
static class Program
{
// list inside your class with the information you need
private static List<string> fileLines;
private static void Main(string[] args)
{
// call the method to read your file and create the list
FirstMethod();
// second method to get a random line, in this case, will return the string
var result = SecondMethod();
Console.WriteLine(result);
Console.ReadLine();
}
private static void FirstMethod()
{
// with this approach you can load one line per string inside your List<>
var yourFile = File.ReadAllLines("C:\\test.txt");
fileLines = new List<string>(yourFile);
}
private static string SecondMethod()
{
// random number starting with 0 and maximum to your list size
var rnd = new Random();
return fileLines[rnd.Next(0, fileLines.Count)];
}
}

Related

Why is the stack count resetting?

For some reason, when the loadStack() method finishes, it's count resets to 0. no idea why.
here's my method:
static Stack<string> Proxies = new Stack<string>();
private static void loadStack()
{
foreach (string s in File.ReadLines(pfile))
{
Proxies.Push(s);
Console.WriteLine(Proxies.Count());
}
}
and here's my main method:
static string pfile;
static void Main(string[] args)
{
pfile = Console.ReadLine();
loadStack();
}
It goes through the entire file fine, but once it finishes the last line, the count resets to 0.
Following code works perfectly AND even after loadStack method is finished, Main function prints "3" as expected. Here is the C# fiddle link for your reference.
public class Program
{
static Stack<string> Proxies = new Stack<string>();
static List<string> lst = new List<string>{"a","b","c"};
public static void Main()
{
loadStack();
Console.WriteLine(Proxies.Count);
}
private static void loadStack()
{
foreach (string s in lst)
{
Proxies.Push(s);
Console.WriteLine(Proxies.Count);
}
}
}

Unable to populate listbox

Im having a bit of trouble with displaying a list in my listbox.
When I had everything in one class, things seemed to work fine but I cant figure out why it doesnt work now. My app, when clicked on the scan button, goes to a different class where there is a new thread created to scan for available bluetooth devices and the a list with those devices is created. Once the list is passed back to a method in Form1 class, it doesnt update the listbox. In debugging mode I could see that there are items on the list but nothing appears in the listbox. The listbox displays items if I did listBox1.Items.Add("Hello World") from the scan button click method. Im sort of stuck here. Ive just started learning C# and if anyone could help me that would be greatly appreciated.
public partial class Form1 : Form
{
int PanelWidth;
bool PanelCalShow;
public Form1()
{
InitializeComponent();
PanelWidth = PanelCal.Width;
PanelCalShow = false;
}
private void button2_Click(object sender, EventArgs e)
{
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
if (PanelCalShow)
{
PanelCal.Width = PanelCal.Width + 10;
if (PanelCal.Width >= PanelWidth)
{
timer1.Stop();
PanelCalShow = false;
this.Refresh();
}
}
else
{
if (PanelCalShow != true)
{
PanelCal.Width = PanelCal.Width - 10;
if (PanelCal.Width <= 0)
{
timer1.Stop();
PanelCalShow = true;
this.Refresh();
}
}
}
}
// Bluetooth connection
private void BtnScan_Click(object sender, EventArgs e)
{
var instance = new BtCom();
instance.Scan();
}
public void LbClientUpdate(List<string> DiscoveredDevices)
{
listBox1.DataSource = DiscoveredDevices;
}
}
and the bluetooth connection class
public class BtCom
{
public List<string> DiscoveredDevices = new List<string>();
Guid mUUID = new Guid("00001101-0000-1000-8000-00805F9B34FB");
public void Scan()
{
Thread bluetoothScanThread = new Thread(new ThreadStart(Scanning));
bluetoothScanThread.Start();
}
BluetoothDeviceInfo[] devices;
public void Scanning()
{
var form1 = new Form1();
BluetoothClient client = new BluetoothClient();
devices = client.DiscoverDevicesInRange();
foreach (BluetoothDeviceInfo d in devices)
{
DiscoveredDevices.Add(d.DeviceName);
}
form1.LbClientUpdate(DiscoveredDevices);
}
}
The reason you aren't seeing any update on your original form is that you are creating a new instance of the Form1 class inside of your BtCom class instead of using the original instance.
One way you could fix this would be to pass the original instance of the form to your BtClass through a parameter to the Scan method, and then pass it along to your Scanning method. This way you will be calling methods on the same instance of the form that's running.
The problem with that is you will be blocking your UI while waiting for the thread to finish (assuming you call bluetoothScanThread.Join() to wait for the thread results).
A slightly different solution would be to use Tasks, with async methods that await results.
To do this, you would have your scan method return a Task<List<string>> (which is a Task that returns a List<string> representing the devices).
Then in form1 you would create an async method (called GetDatasource below) that creates an instance of your BtCom class, awaits the scan method, and returns the Task<List<string>>.
Finally, you would also make the Click method async and have it assign await the GetDatasource method and assign the Datasource when it returns.
By doing it this way, you isolate the BtCon class from having to know any details about the Form1 class, which is a good habit to get into because you end up creating more reusable and independent code.
Here's an example of all those words in code:
Make the scan method return a Task<List<string>> that can be used for the datasource (and have Scanning return a List<string>). Notice that the list is now private to the scanning method. It's a good practice to limit the scope of variables to only the level they are needed.:
public class BtCom
{
Guid mUUID = new Guid("00001101-0000-1000-8000-00805F9B34FB");
public Task<List<string>> Scan()
{
var bluetoothScanTask = Task.Factory.StartNew(Scanning);
bluetoothScanTask.Wait();
return bluetoothScanTask;
}
private List<string> Scanning()
{
BluetoothClient client = new BluetoothClient();
devices = client.DiscoverDevicesInRange();
List<string> discoveredDevices = new List<string>();
foreach (BluetoothDeviceInfo d in devices)
{
discoveredDevices.Add(d.DeviceName);
}
return discoveredDevices;
}
}
Then, write an async method that will get the datasource by creating a new instance of this class, and await for the method to return. Also, make the Click method async so it can await the datasource method:
public partial class Form1 : Form
{
// Other form code omitted...
private async void BtnScan_Click(object sender, EventArgs e)
{
listBox1.DataSource = await Task.Run(GetDatasource);
}
private async Task<List<string>> GetDatasource()
{
var btCom = new BtCom();
List<string> results = await btCom.Scan();
return results;
}
Now your users can click the button and the form will continue to respond while the scanning takes place, and your listbox will populate when the scan method finishes.
For more on async and await, check your favorite search engine (like this page on Asynchronous programming, for example).

Adding list to listbox one by one

I need to add my list to my listbox. I searched through all the questions on this site but none work I always get things like listbox1.spelers in my listbox.
Here is the code I have now.
private void btnAdd_Click(object sender, EventArgs e)
{
Speler speler1 = new Speler(tbNaam.Text, tbAge.Text);
List<Speler> spelers = new List<Speler>();
spelers.Add(speler1);
listBox1.DataSource = spelers;
}
Also tried with the ToArray but it still didn't work.
SOLVED
You're re-binding the control to a list of exactly one element every time. So the control will only ever have one element.
Keep the list in a higher scope. For example, if this class is persistent in memory (that is, not a web application) then make it a class-level member:
private List<Speler> spelers = new List<Speler>();
private void btnAdd_Click(object sender, EventArgs e)
{
Speler speler1 = new Speler(tbNaam.Text, tbAge.Text);
spelers.Add(speler1);
listBox1.DataSource = spelers;
// maybe call listBox1.DataBind() here? it's been a while since I've had to use forms
}
That way you're always adding another element to the same list, instead of creating a new list every time.
If you are using Windows Forms application, you can use a BindingDource:
Speler speler1 = new Speler(tbNaam.Text, tbAge.Text);
List<Speler> spelers = new List<Speler>();
spelers.Add(speler1);
var bs = new BindingSource();
bs.DataSource = spelers;
listBox1.DataSource = bs;
Good example is here : Console App
using System;
namespace Enumeration
{
using System;
using System.Collections;
// implements IEnumerable
class ListBoxTest : IEnumerable
{
private string[] strings;
private int ctr = 0;
// private nested implementation of ListBoxEnumerator
private class ListBoxEnumerator : IEnumerator
{
// member fields of the nested ListBoxEnumerator class
private ListBoxTest currentListBox;
private int index;
// public within the private implementation
// thus, private within ListBoxTest
public ListBoxEnumerator(ListBoxTest currentListBox)
{
// a particular ListBoxTest instance is
// passed in, hold a reference to it
// in the member variable currentListBox.
this.currentListBox = currentListBox;
index = -1;
}
// Increment the index and make sure the
// value is valid
public bool MoveNext()
{
index++;
if (index >= currentListBox.strings.Length)
return false;
else
return true;
}
public void Reset()
{
index = -1;
}
// Current property defined as the
// last string added to the listbox
public object Current
{
get
{
return(currentListBox[index]);
}
}
} // end nested class
// Enumerable classes can return an enumerator
public IEnumerator GetEnumerator()
{
return (IEnumerator) new ListBoxEnumerator(this);
}
// initialize the listbox with strings
public ListBoxTest(params string[] initialStrings)
{
// allocate space for the strings
strings = new String[8];
// copy the strings passed in to the constructor
foreach (string s in initialStrings)
{
strings[ctr++] = s;
}
}
// add a single string to the end of the listbox
public void Add(string theString)
{
strings[ctr] = theString;
ctr++;
}
// allow array-like access
public string this[int index]
{
get
{
if (index < 0 || index >= strings.Length)
{
// handle bad index
}
return strings[index];
}
set
{
strings[index] = value;
}
}
// publish how many strings you hold
public int GetNumEntries()
{
return ctr;
}
}
public class EnumerationTester
{
public void Run()
{
// create a new listbox and initialize
ListBoxTest currentListBox =
new ListBoxTest("Hello", "World");
// add a few strings
currentListBox.Add("Who");
currentListBox.Add("Is");
currentListBox.Add("John");
currentListBox.Add("Galt");
// test the access
string subst = "Universe";
currentListBox[1] = subst;
// access all the strings
foreach (string s in currentListBox)
{
Console.WriteLine("Value: {0}", s);
}
}
[STAThread]
static void Main()
{
EnumerationTester t = new EnumerationTester();
t.Run();
}
}
}

Pass Values from Form -> Class -> Form C#

I have 2 Forms: V.Batch and V.BatchEdit and a Class: M.Batch
In V.Batch there is a DataGrid. I want to pass the value I get from the DataGrid to V.BatchEdit and the get set method is in M.Batch.
The problem here is that the value isn't passed properly in V.BatchEdit. It returns 0.
Here is the code
V.Batch:
M.Batch bt;
public Batch()
{
bt = new M.Batch();
InitializeComponent();
}
private void metroButton3_Click_1(object sender, EventArgs e)
{
bt.batchNum = Convert.ToInt32((metroGrid2.CurrentCell.Value).ToString());
V.BatchEdit bEdit = new V.BatchEdit();
this.Hide();
bEdit.Show();
}
M.Batch:
public int batchNum;
public int BatchNum
{
set { batchNum = value; }
get { return batchNum; }
}
V.BatchEdit
static M.Batch bt = new M.Batch();
DataSet a = bt.getBatch(bt.batchNum);
public BatchEdit()
{
db = new Database();
InitializeComponent();
System.Windows.Forms.MessageBox.Show(bt.batchNum.ToString() + "Batchedit");
try
{
metroTextBox1.Text = a.Tables[0].Rows[0][2].ToString();
}
catch (Exception exceptionObj)
{
MessageBox.Show(exceptionObj.Message.ToString());
}
}
I'm new to coding and c#. I'm not sure if I placed static even though it should not be static or what.
Yes, you are using static improperly here.
The easiest way to see what's going wrong is to notice that you are calling new M.Batch() twice. That means you have two different instances of M.Batch in your application. And nowhere in your code do you attempt to share those instances.
What you should be doing is passing your instance of M.Batch from one form to another, e.g. in the constructor:
// V.Batch
bt.batchNum = Convert.ToInt32((metroGrid2.CurrentCell.Value).ToString());
V.BatchEdit bEdit = new V.BatchEdit(bt);
this.Hide();
bEdit.Show();
// V.BatchEdit
private M.Batch bt;
private DataSet a;
public BatchEdit(M.Batch batch)
{
this.bt = batch;
this.a = this.bt.getBatch(bt.batchNum)
// Rest of your code here.
}
If You don't need the 'M.Batch' class for something else and you only use it for passing the value to V.BaychEdit, just declare a public property in V.BatchEdit like you did in M.Batch and use it like this:
V.BatchEdit bEdit = new V.BatchEdit();
bEdit.BatchNum = Convert.ToInt32((metroGrid2.CurrentCell.Value).ToString());
Your problem is that although your using statics you're still assigning a new instance to the static field.

How to populate a lstbox from a ,txt file at startup

I need to populate a listbox from a text file at startup. I also need to have the firt 2 lines eliminated from the listbox along with all blank lines, but that isn't to important right now. I am currently stuck at getting the listbox populated at all. Here is my code so far:
struct CDCLocationEntry
{
public string name;
}
public partial class StartupForm : Form
{
private List<CDCLocationEntry> CDCList = new List<CDCLocationEntry>();
public StartupForm()
{
InitializeComponent();
}
private void ReadFile()
{
try
{
StreamReader inputFile;
string line;
CDCLocationEntry entry = new CDCLocationEntry();
inputFile = File.OpenText("P3S1 Data File For Import.txt");
while (!inputFile.EndOfStream)
{
line = inputFile.ReadLine();
CDCList.Add(entry);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void DisplayText()
{
foreach (CDCLocationEntry entry in CDCList)
{
CDCLocationListBox.Items.Add(entry.name);
}
}
private void StartupForm_Load(object sender, EventArgs e)
{
ReadFile();
DisplayText();
}
visual studio is say my problem is here:
struct CDCLocationEntry
{
public string name;
}
the message I'm getting is:
Warning 1 Field 'Project_3___Section_1.CDCLocationEntry.name' is never
assigned to, and will always have its default value null
none of my notes or online help is giving me an answer for this.
Any help that you can provide would be greatly appreciated
You need to create a CDCLocationEntry instance inside the loop and assign, at this instance property name, the line coming from your file
inputFile = File.OpenText("P3S1 Data File For Import.txt");
while (!inputFile.EndOfStream)
{
CDCLocationEntry entry = new CDCLocationEntry();
entry.name = inputFile.ReadLine();
CDCList.Add(entry);
}
Your actual code creates just one instance of CDCLocationEntry outside the loop and, without assigning anything to the name property, adds this same instance in every loop.

Categories