Firstly, most of my experience with coding is through python hence my use of global
I have a list and I want to be able to search the list and find all words that are of x length. My main issue is not knowing how to call a function from inside an event listener.
So myList is generated inside of my function functionOne, I am then wanting to use this list inside functionTwo and then finally I want to call it when buttonOne is clicked. E.g buttonOne_Click ....
This is what I have so far for functionOne
public List<string> noDup(List<string> myList)
{
var convert = myList.ConvertAll(i => i.ToLower());
List<string> remove = convertLower.Distinct().ToList();
return remove;
}
functionTwo
public List<string> length(List<string> myList)
{
int i = int.Parse(lengthSearch.Text);
List<string> temp = new List<string>();
foreach(string item in myList)
{
if(item.Length == i)
{
temp.Add(item);
}
}
searchResult.Text = string.Join(",", temp);
}
And finally my event listener
private void button_Click(object sender, EventArgs e)
{
length(remove);
}
NOTE: remove is the list I am trying to work with
But there is no output with this code because I get an error saying remove doesn't exist in this context, I'm unsure how I make this list global
Put all the functions in the same class and use noDup on your list instance.
public List<string> noDup(List<string> myList)
{
var convert = myList.ConvertAll(i => i.ToLower());
List<string> remove = convertLower.Distinct().ToList();
return remove;
}
public void length(List<string> myList)
{
int i = int.Parse(lengthSearch.Text);
List<string> temp = new List<string>();
foreach(string item in myList)
{
if(item.Length == i)
{
temp.Add(item);
}
}
searchResult.Text = string.Join(",", temp);
}
private void button_Click(object sender, EventArgs e)
{
var remove = noDup(yourInputList);
length(remove);
}
We'll here's the general idea how to achieve this in a win forms c# application.
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
private List<string> _remove;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
length(_remove);
}
public List<string> noDup(List<string> myList)
{
var convert = myList.ConvertAll(i => i.ToLower());
_remove = convertLower.Distinct().ToList();
}
public List<string> length(List<string> myList)
{
int i = int.Parse(lengthSearch.Text);
List<string> temp = new List<string>();
foreach (string item in myList)
{
if (item.Length == i)
{
temp.Add(item);
}
}
searchResult.Text = string.Join(",", temp);
}
}
}
Mind this doesn't build since I just used your code. For example the length method should return a List<string> but it doesn't. You would probably want to change the list that's passed in and then return it, or mutate the class level variable _remove.
Either way the event handler button1_Click needs to work with a class level variable (such as _remove that I added) or call a method that will return the list (as is present in the other anwser by Zbigniew.)
Related
I need to see if a dropdown box has selected a key out of a dictionary. The dictionary is in another method (I believe its called a method). I've been searching how to make the dictionary global, but i can't figure out how to do it. Maybe there is a better way?
Thanks for any help, I wrote some code to show what I'm trying to accomplish below.
public void Dictionary()
{
var names = new Dictionary<string, double[]>();
names.Add("Kevin", new[] { 74.5, 6.35});
names.Add("Rob", new[] { 2.5, 9.46});
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
foreach (var kvp in names)
{
if combobox.Text == kvp.Key
{
solution = true;
}
}
}
Another way you could handle this would be to return the Dictionary.
public Dictionary GetDictionary()
{
var names = new Dictionary<string, double[]>();
names.Add("Kevin", new[] { 74.5, 6.35});
names.Add("Rob", new[] { 2.5, 9.46});
return names;
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
foreach (var kvp in GetDictionary())
{
if (combobox.Text == kvp.Key)
{
solution = true;
}
}
}
Making the method public is what makes it accessible globally. There are a couple of missing pieces: the method itself is missing a return type, and it needs to be directly called from the combobox1_SelectedIndexChanged method.
It is best practice to not use a reserved name from the .NET framework in custom code - here I have changed the method name to GetDropdownChoices, added a return type, and then called the method outside of the foreach loop. For perfomance optimization, one suggestion is to use the .ContainsKey method instead looping through each item in a dictionary.
public Dictionary<string, double[]> GetDropdownChoices()
{
var names = new Dictionary<string, double[]>();
names.Add("Kevin", new[] { 74.5, 6.35});
names.Add("Rob", new[] { 2.5, 9.46});
return names;
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
var choices = GetDropdownChoices();
if (choices.ContainsKey(combobox.Text))
{
solution = true;
}
}
public class Foo
{
private readonly Dictionary<string, double[]> _names;
public Foo()
{
_names = new Dictionary<string, double[]>();
}
public void Dictionary() // note: this is just name taken from initial question
{
_names.Add("Kevin", new[] { 74.5, 6.35 });
_names.Add("Rob", new[] { 2.5, 9.46 });
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
foreach (var kvp in _names)
{
if (combobox.Text == kvp.Key) // assuming you have already a declared "combobox" member
{
solution = true;
}
}
}
}
I have two classes, one contains the value I want to maintain and it is declared as [serializable] since I may want to store the results in a file later.
namespace WindowsFormsApp1
{
[Serializable]
public class Class1
{
string Something = "";
public Class1(string something)
{
Something = something;
}
public Class1()
{
Something = "";
}
public string something
{
get { return Something; }
set { Something = value; }
}
}
}
The second declares a List of this class along with a few access functions
namespace WindowsFormsApp1
{
class Class2
{
public static List<Class1> aClass = new List<Class1>();
public static int cnt = 0;
public void AddStaticString(Class1 aString)
{
aClass.Add(aString);
cnt++;
}
public string GetAllStrings()
{
string aFullString = "";
int cnt = 0;
while (cnt < aClass.Count)
{
aFullString = aClass[cnt].something;
cnt++;
}
return aFullString;
}
}
}
Now a simple bit of code to add to the LIST and try to extract it
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Class1 aClass = new Class1();
Class2 aSClass = new Class2();
aClass.something = "AAAAA";
aSClass.AddStaticString(aClass);
aClass.something = "BBBBB";
aSClass.AddStaticString(aClass);
aClass.something = "CCCCC";
aSClass.AddStaticString(aClass);
richTextBox1.Text = aSClass.GetAllStrings();
}
}
}
The richTextBox always displays the last item only (CCCCC), even though I can see the proper values being input into the LIST.
Can I not access the members of the LIST with aFullString = aClass[cnt].something; ?
You are just returning the last string from the list in GetAllStrings. Rather you could append it to existing item, or maybe separate them using comma, whatever you want.
For example, you can append those values using simply:
aFullString += aClass[cnt].something + ",";
But that would leave a comma at the end of the string.
Rather, if you need comma separated values, you could just join the strings using LINQ,
public string GetAllStrings()
{
return string.Join(",", aClass.Select(item => item.something));
}
Also, in button1_Click you are adding the same instance of Class1 to the list in Class2. If you need separate instances of the class, you should create new instance before calling AddStaticString:
private void button1_Click(object sender, EventArgs e)
{
Class2 aSClass = new Class2();
Class1 aClass = new Class1();
aClass.something = "AAAAA";
aSClass.AddStaticString(aClass);
aClass = new Class1();
aClass.something = "BBBBB";
aSClass.AddStaticString(aClass);
aClass = new Class1();
aClass.something = "CCCCC";
aSClass.AddStaticString(aClass);
richTextBox1.Text = aSClass.GetAllStrings();
}
You should, but the way you are assigning that aFullString variable will always show the last value of the list.
You should try it like this:
public string GetAllStrings()
{
string aFullString = "";
int cnt = 0;
while (cnt < aClass.Count)
{ //+ to keep the previous values too
aFullString += aClass[cnt].something;
cnt++;
}
return aFullString;
}
In this method:
public string GetAllStrings()
{
string aFullString = "";
int cnt = 0;
while (cnt < aClass.Count)
{
aFullString = aClass[cnt].something;
cnt++;
}
return aFullString;
}
You set aFullString to the last collection item's something.
What you want is probably string concatenation. You don't need while loop - for or foreach loop suit better, or even string.Join would be the best option:
public string GetAllStrings()
{
return String.Join(" ", aClass.Select(x => x.something);
}
Please, note that your code has many style and naming errors, unused or useless variables like class members Something and cnt, and doesn't make much sense in general.
You need to follow C# naming conventions and rules to make your code readable and understandable by other developers.
As the title says, I need to pass a list of hashtables from a regular class to a form class to be rendered in a DataGridView. What I've got so far is this:
namespace somenamespace
{
class aldeloUpdater
{
private static string client = "chanchitos";
private static string establishment = "c1";
static void Main()
{
try
{
var guiForm = new GuiForm(); // Instantiating the Form-derived class.
string deliveriesListResp = getOrders();
Processing...
foreach (...)
{
if ((bool)DBresponse["status"])
{
guiForm.dataGridViewProducts = (List<Hashtable>)DBresponse["deliveriesSaved"]; // Passing the data to the DataGridView.
foreach (Hashtable delivery in (List<Hashtable>)DBresponse["deliveriesSaved"])
{
string updateDeliveryResponse = updatePedidoInDomicilios(delivery["domiciliosOrderId"].ToString(), 2, DBresponse["errmsg"].ToString());
}
}
else
{
Processing...
}
}
guiForm.ShowDialog(); // Showing the form.
More processing...
}
catch (Exception e)
{
Console.WriteLine("Exception details: " + e.ToString());
Console.ReadLine();
}
}
More methods...
}
Now the Form class looks like this:
namespace somenamespace
{
public partial class GuiForm : Form
{
public List<Hashtable> dataGridViewProducts; // Variable used to store the data to be rendered by the DataGridView.
public GuiForm()
{
InitializeComponent();
}
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
}
private void GuiForm_Load(object sender, EventArgs e)
{
int index = 0;
foreach (Hashtable product in dataGridViewProducts)
{
dataGridView1.Rows.Add();
dataGridView1.Rows[index].Cells[0].Value = product["productName"];
dataGridView1.Rows[index].Cells[1].Value = product["userName"];
dataGridView1.Rows[index].Cells[2].Value = product["dateAndTime"];
dataGridView1.Rows[index].Cells[3].Value = product["domiciliosOrderId"];
index++;
}
}
Some more methods.
}
}
For now this code works just fine and the data is shown in the DataGridView, nonetheless I feel like there must be a better way to achieve this goal, it's just that I'm new to C#. I will appreciate suggestions and even more a code sketch of how you would do this in a better way.
Thanks.
I'm trying to count the number of *.tmp files in the computer. When I click on a button the labelbox should start increasing the count number for each search of .tmp file. my below coding does not seems to be working.
Any help is much appreciated.
Also when I click on button to get the number of tmp files; the lable box should start showing the increase in count like 1,2,,,,,56,,89,,,etc rather than showing just the total number of files.
namespace finalclean {
public partial class FinalClean : Form {
public FinalClean() {
InitializeComponent();
}
int count = 0;
private void button1_Click(object sender, EventArgs e) {
String path = Environment.ExpandEnvironmentVariables(#"c:\windows");
try {
foreach (string dirPath in Directory.GetDirectories(path)) {
foreach (string filePath in Directory.GetFiles(dirPath)) {
string filename = Path.GetFileName(filePath);
if (filename.Equals("*.tmp")) {
count++;
}
}
}
}
catch (System.Exception excpt) {
//Console.WriteLine(excpt.Message);
}
textBox1.Text = (count.ToString());
}
}
}
You could just use:
var count = Directory.EnumerateFiles(#"C:\Windows\", "*.tmp",
SearchOption.AllDirectories).Count();
Your code doesn't work because you're not visiting all the directories, but only the fist one (C:\Windows).
If you make it recursive it can do the trick for you.
internal class Program
{
private static void Main(string[] args)
{
var myClass = new Visitor();
myClass.OnNewFileFound +=Progress;
myClass.CountTmpFiles();
Console.Read();
}
private static void Progress(int i)
{
Console.WriteLine(i); //update textbox here
}
}
public class Visitor
{
public event Action<int> OnNewFileFound;
private int count = 0;
public int CountTmpFiles()
{
var path = Environment.ExpandEnvironmentVariables(#"c:\windows");
VisitDir(path);
return count;
}
private void VisitDir(string path)
{
try
{
foreach (var directory in Directory.GetDirectories(path))
{
VisitDir(directory); //recursive call here
}
foreach (var filePath in Directory.GetFiles(path, "*.tmp", SearchOption.TopDirectoryOnly))
{
count++;
if (OnNewFileFound != null)
{
OnNewFileFound(count);
}
}
}
catch (System.Exception excpt)
{
//Console.WriteLine(excpt.Message);
}
}
}
And yes, if you're only counting files, then I doesn't make sense to write your own code. You just use Directory.EnumerateFiles as Andrew and Hamlet Hakobyan suggested.
Ok, so I have a question regarding the EventArgs that can be passed when an event is triggered. I am designing a small, basic search engine and have a class called Query that contains a method Search. When this method is called, I want to trigger an event which will pass the results to be storred in a variety of cache class instances (SizeBoundedCache and TimeBoundedCache). So I thought the best way to do this would be to use an event.
The delegate is declared like this ->
public delegate void CacheStoreDelegate(object sender, EventArgs e);
The rest of the code within the Query class relevant to this question is here (uses Linq) ->
public event CacheStoreDelegate AddToCache;
public virtual void OnQuery (EventArgs e)
{
if(AddToCache != null)
AddToCache(this, e);
}
public Query()
{
}
public Query(string queryString, OOP5.Provided.QueryOperator op)
{
//Access and set the terms array
this.Terms = OOP5.Provided.QueryUtils.GetTermsFromString(queryString);
this.Operator = op;
}
public static IEnumerable<string> Search (this SearchCore s, IQuery q)
{
// Accept a query and return IEnumerable<string> of
// all document IDs matching that query
if (q.Operator == QueryOperator.Any)
{
var GetAnyMatch = from single_query in q.Terms
group s.Search(single_query)
by s.documents.Keys
into results
where results.Count >= 1
select results[0];
this.OnQuery(GetAnyMatch);
return GetAnyMatch;
}
if (q.Operator == QueryOperator.All)
{
var GetAllMatch = from single_query in q.Terms
group s.Search(single_query)
by s.documents.Keys
into results
where results.Count >= q.Terms.Lengthselect results[0];
this.OnQuery(GetAllMatch);
return GetAllMatch;
}
}
All the cache classes will be notified whenever a search is called and I also need thme to receive the results.
Thanks so much in advance for the help. Also, if there is a more elegant way to do this that I am not thinking of, please chime in. Cheers!
You could create your own EventArgs implementation:
class QueryResultEventArgs : EventArgs
{
public IEnumerable<string> Results { get; private set; }
public QueryResultEventArgs(IEnumerable<string> results)
{
Results = results;
}
}
...
public delegate void CacheStoreDelegate(object sender, QueryResultEventArgs e);
...
this.OnQuery(new QueryResultEventArgs(GetAnyMatch));
Make a class of type CacheStoreEventArgs deriving from eventargs
public class CacheStoreEventArgs:eventargs
{
private IEnumerable<string> Data;//List<string> better
public IEnumerable<string> data
{
get { return Data; }
set { this.Data = value; }
}
public CacheStoreEventArgs(IEnumerable<string> NewData)
{
this.data = NewData;
}
}
then declare the event(use predefined generic one,so no need to declare one)
public event EventHandler<CacheStoreEventArgs> AddToCache;
inside your method search you call your method "On...."
public static IEnumerable<string> Search (this SearchCore s, IQuery q)
{
//after you get query result
CacheStoreEventArgs cs = new CacheStoreEventArgs(queryresultvariablehere);
//and call your method now with the instance of your derived eventargs class
OnQuery(cs);
}
public virtual void OnQuery (CacheStoreEventArgs e)
{
try
{
EventHandler<CacheStoreEventArgs> temp = AddToCache
if( temp != null)
temp(this,e);
}
catch(Exception ex)
{
//exception handling
}
}