Extension method must be defined in a non-generic static class - c#

I'm getting the above error. I saw other similar posts on this error but I don't seem to find where the problem is. I changed my class type to static and the error resists. This is the entire code to my main form class:
I Edited my class. This is how it looks like now and the error has changed to:Missing partial modifier on declaration of type 'PhoneFind.frmMain'; another partial declaration of this type exists.
namespace PhoneFind
{
public partial class frmMain : Form
{
// the path to the temporary file to store the webresponse
String path = "c:\\Temp\\webresponse.txt";
public frmMain()
{
InitializeComponent();
comboSelectSearchEngine.SelectedIndex = 0;
ofdPhones.Filter = "txt files (*.txt)|*.txt";
listbxMessages.Items.Clear();
addItemToListBox(listbxMessages, "Welcome to ActionBase Phone Find!");
addItemToListBox(listbxMessages, "Select the file containing the numbers.");
radioNumbers.Checked = true;
}
private void frmMain_Load(object sender, EventArgs e)
{
}
private void btnLoadFile_Click(object sender, EventArgs e)
{
if (ofdPhones.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
txtFile.Text = ofdPhones.FileName;
// Read the file line by line and add the numbers to the numbers listbox.
listbxNumbers.Items.Clear();
String line;
int numbersCounter = 0;
System.IO.StreamReader file = new System.IO.StreamReader(ofdPhones.FileName);
while ((line = file.ReadLine()) != null)
{
listbxNumbers.Items.Add(line.Trim());
numbersCounter++;
}
addItemToListBox(listbxMessages, ofdPhones.FileName + " loaded.");
addItemToListBox(listbxMessages, numbersCounter + " records found in the file.");
}
}
// add item to the listbox and move scroll to the end of the listbox for the latest messages to be visibile to the viewer
private void addItemToListBox(ListBox listbox, String item)
{
listbox.Items.Add(item);
listbox.SelectedIndex = (listbox.Items.Count - 1);
}
private void radioNumbers_CheckedChanged(object sender, EventArgs e)
{
if (!radioNumbers.Checked)
{
grpbxNumbers.Text = "Names and Addresses";
}
else
{
grpbxNumbers.Text = "Numbers";
}
}
private void btnRun_Click(object sender, EventArgs e)
{
if (listbxNumbers.Items.Count == 0)
{
MessageBox.Show("No records have been loaded." + "\n" + "Use the browse button to load records.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else if (!CheckForInternetConnection())
{
MessageBox.Show("No internet connection.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
String response;
switch (comboSelectSearchEngine.SelectedIndex)
{
case 0: // Hitta.se
foreach (String item in listbxNumbers.Items)
{
WebRequestObj request = new WebRequestObj(item, "hitta");
response = request.sendRequest();
if (response.Equals("Error"))
{
addItemToListBox(listbxMessages, "Error sending '" + item + "' to the server.");
}
else
{
//create a temporary file to work on the response
StreamWriter sw;
if (!File.Exists(path)) {
sw = File.CreateText(path);
}
try
{
File.WriteAllText(path, String.Empty); // clear the content of the file
sw = File.AppendText(path);
sw.WriteLine(response);
sw.Flush();
sw.Close();
String s = findResultType(path);
MessageBox.Show(s);
}
catch (IOException ioe)
{
MessageBox.Show(ioe.Message,"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
break;
}
}
}
public bool CheckForInternetConnection()
{
try
{
using (var client = new System.Net.WebClient())
using (var stream = client.OpenRead("http://www.google.com"))
{
return true;
}
}
catch
{
return false;
}
}
/*
* findResultType
* gets the web response and finds out if the matching result of the search termis one of the following:
* 1. one person (oneperson)
* 2. one company (onecompany)
* 3. more than one person, no company (manypersonnocompany)
* 4. no person, more than one company (nopersonmanycompany)
* 5. more than one person, more than one company (manypersonmanycompany)
* 6. no person, no company (nopersonnocompany)
*/
public String findResultType(String reponsepath)
{
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc.Load(reponsepath);
List<String> itemList = new List<String>();
IEnumerable<String> v = null;
var item = doc.DocumentNode.SelectNodes("//body[#id='person']");
if (item != null)
{
v = item.Select(p => p.InnerText);
itemList = v.ToList();
if (itemList.Count == 1)
return "oneperson";
}
else
{
item = doc.DocumentNode.SelectNodes("//body[#id='company']");
if (item != null)
{
v = item.Select(p => p.InnerText);
itemList = v.ToList();
if (itemList.Count == 1)
return "onecompany";
}
}
//for (int i = 0; i < itemList.Count; i++)
//{
// MessageBox.Show(itemList[i]);
// //console.writeline(itemlist[i]);
//}
//console.writeline(itemlist.count + " results found.");
return "";
}
}
}

This is your first problem:
public static class frmMain : Form
You can't derive a static class from another class. A static class always implicitly derives from Object. You also can't have non-static members in static classes.
So basically, you can't put your extension method in your frmMain class (which should be renamed to follow .NET naming conventions and to be somewhat more descriptive at the same time). Why did you want to put the extension method in that class anyway?
I can't even see an extension method in the code you've posted - did you remove it? Is it in some other class you haven't posted?
Fundamentally, I think you need to take a step back. It sounds like you've reacted to the compiler error message without really understanding it fully. Read up on extension methods, read up on what static classes are, until you really understand why you don't want your form class to be static, and why you do want to make the class that contains your extension method static.

A static class cannot have public constructors. Moreover, static forms are pointless, as you need an instance of them to show.
If you have an extension method (I don't see any...), you have to move it into a separate static class which you cannot create instances of:
static class MyExtensions
{
public static void Extend(this Object o) {}
}

You should always put your extension methods in a separate static class.
You can't fix the problem by simply marking a class as static. That changes the entire meaning of the class. Instead, create a new class for just extension methods.
For example:
public static class Extensions
{
public void SomeExtension(this object arg)
{
...
}
}

Related

UI Not Loading When Using While In Foreach Loop

I am making a program which you can create and load in a flashcard pack using csv files. When a csv file is chosen it opens other UI with the question, answer and image for a flashcard and will keep on looping until all the flashcards in the pack are gone through using a foreach loop.
However the foreach loop would keep on looping without the user pressing the next button. To fix this I did:
while (Continue() == false) { } //this is at the end of the foreach loop
}
}
private bool Continue()
{
if (btn_NextFlashcard_WasClicked) return true;
Application.DoEvents();
Thread.Sleep(250);
Application.DoEvents();
return false;
}
private bool btn_NextFlashcard_WasClicked;
private void btn_NextFlashcard_Click(object sender, EventArgs e)
{
btn_NextFlashcard_WasClicked = true;
}
This fixed the problem of it looping again without the button for the next flashcard being pressed but now it doesn't even open the second UI for me to press the next flashcard button.
How would I fix this? Any help would be greatly appreciated.
Code for foreach loop:
public void ReadFlashcardPack(string file)
{
var records = engine.ReadFile(file);
foreach (var record in records)
{
Console.WriteLine("New foreach loop");
lblQuestion.Text = record.question;
lblAnswer.Text = record.answer;
lblAnswer.Visible = false;
btn_NextFlashcard_WasClicked = false;
//check if there is an image
if (record.image == "FALSE")
{
Image.Hide();
}
else
{
Image.Show();
Image.Image = Properties.Resources.test_image;
}
while (Continue() == false) { }
}
}
The records also come from a class: [DelimitedRecord(",")]
public class FlashcardPack
{
public string question;
public string answer;
public string image;
}
And then a new instance of FileHelpers engine is made private FileHelperEngine<FlashcardPack> engine = new FileHelperEngine<FlashcardPack>(); to read the csv file and every time the foreach loop loops record.question, record.answer and record.image changes depending on what line the loop is on.
One idea that comes to mind is to store the list of records outside of the method, keep track of the next record that should be read, and modify the method to just read the next record.
Then, in your click event, you can just call the method again until all records have been read.
private string filePath = #"f:\private\temp\temp.csv"; // Use your file path here
private List<FlashcardPack> records;
private int nextRecord;
public void ReadNextRecord()
{
if (records == null)
{
records = engine.ReadFile(filePath).ToList();
nextRecord = 0;
}
else if (nextRecord >= records.Count)
{
// Do something when all records have been read
nextRecord = 0;
}
// Get next record and increment our variable
var record = records[nextRecord++];
lblQuestion.Text = record.question;
lblAnswer.Text = record.answer;
lblAnswer.Visible = false;
btn_NextFlashcard_WasClicked = false;
//check if there is an image
if (record.image == "FALSE")
{
Image.Hide();
}
else
{
Image.Show();
Image.Image = Properties.Resources.test_image;
}
}
private void btn_NextFlashcard_Click(object sender, EventArgs e)
{
ReadNextRecord();
}
Here's a working sample that uses the concept above which might help you get your code working, since I can't see your whole project:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private List<Flashcard> flashcards;
private int nextRecord;
// Use a valid path on your system here (the file doesn't need to exist)
private const string FilePath = #"f:\public\temp\temp.csv";
private void LoadFlashcards()
{
flashcards = Engine.ReadFile(FilePath);
nextRecord = 0;
}
public void DisplayNextFlashcard()
{
if (flashcards == null)
{
LoadFlashcards();
}
else if (nextRecord >= flashcards.Count)
{
// Do something when all records have been read
nextRecord = 0;
}
var flashcard = flashcards[nextRecord++];
lblQuestion.Text = flashcard.Question;
lblAnswer.Visible = false;
lblAnswer.Text = flashcard.Answer;
Image.Visible = flashcard.Image;
Image.Image = Properties.Resources.FlashcardImage;
}
private void btn_NextFlashcard_Click(object sender, EventArgs e)
{
DisplayNextFlashcard();
}
}
class Flashcard
{
public string Question { get; set; }
public string Answer { get; set; }
public bool Image { get; set; }
public static Flashcard Parse(string csvLine)
{
if (csvLine == null) throw new ArgumentNullException(nameof(csvLine));
var parts = csvLine.Split(',').Select(item => item.Trim()).ToList();
if (parts.Count != 3) throw new FormatException(
"csvLine does not contain 3 comma-separated items.");
return new Flashcard
{
Question = parts[0],
Answer = parts[1],
Image = !parts[2].Equals("FALSE", StringComparison.OrdinalIgnoreCase)
};
}
}
class Engine
{
public static List<Flashcard> ReadFile(string filePath)
{
if (filePath == null) throw new ArgumentNullException(nameof(filePath));
if (!File.Exists(filePath)) CreateFile(filePath);
return File.ReadAllLines(filePath).Select(Flashcard.Parse).ToList();
}
private static void CreateFile(string filePath)
{
File.CreateText(filePath).Close();
File.WriteAllText(filePath,
"What is more useful when it is broken?, An egg, TRUE\n" +
"What belongs to you but other people use it more?, Your name, FALSE\n" +
"I have three eyes all in a row. When the red one opens " +
"no one can go. What am I?, A traffic light, TRUE");
}
}

C# Form App - stop execution of all code from a helper method that resides in a helper class

I just learned how to pass arguments into methods, so I'm refactoring my code to make it cleaner. I have created a new "ValidateInput" class which holds a ValidateFinancialsInput method which I pass a string into. It then checks the string to see if it is correct, if it's not I want to show a messageBox, then stop execution of ALL of the code. If i use "return;", it just resumes execution of the Parent method. How do I stop execution of all of the code within the ValidateFinancialsInput method? I tried researching this for a while to no avail. Here is my code:
Class Parent
{
private void button2_Click(object sender, EventArgs e)
{ var CompanyVar = comboBox1.Text;
ValidateInput vi = new ValidateInput();
vi.ValidateFinancialsInput(CompanyVar);
//the rest of my code for the application is here
//the rest ...
//the rest...
}
}
class ValidateInput
{
public void ValidateFinancialsInput(string Co)
{
string[] validCompany = { "BVV", "LWDO" };
if (validCompany.Contains(Co) == false)
{
MessageBox.Show("You have entered an invalid company.");
//what do I put here to stop all code execution?
}
}
}
You should try and use return values state intent to calling methods
Class Parent
{
private void button2_Click(object sender, EventArgs e)
{ var CompanyVar = comboBox1.Text;
ValidateInput vi = new ValidateInput();
if(!vi.ValidateFinancialsInput(CompanyVar))
{
MessageBox.Show("You have entered an invalid company.");
return;
}
//the rest of my code for the application is here
//the rest ...
//the rest...
}
}
class ValidateInput
{
public bool ValidateFinancialsInput(string Co)
{
string[] validCompany = { "BVV", "LWDO" };
if (validCompany.Contains(Co) == false)
{
return false;
}
return true;
}
}
What I'm doing here is returning a true|false value to indicate whether the validation has passed, if it has not passed then I display the MessageBox, else it continues the execution of the "other" code.
Hope this helps
The simplest way is with an exception:
class Parent
{
private void button2_Click(object sender, EventArgs e)
{
try
{
var CompanyVar = comboBox1.Text;
ValidateInput vi = new ValidateInput();
vi.ValidateFinancialsInput(CompanyVar);
//the rest of my code for the application is here
//the rest ...
//the rest...
}
catch (ValidationException ex)
{
MessageBox.Show(ex.Message);
}
}
}
class ValidationException : Exception
{
public ValidationException(string message) : base(message)
{
}
}
class ValidateInput
{
public void ValidateFinancialsInput(string Co)
{
string[] validCompany = { "BVV", "LWDO" };
if (validCompany.Contains(Co) == false)
{
throw new ValidationException("You have entered an invalid company.");
}
}
}
This will stop execution of ValidateFinancialsInput and in button2_Click move execution inside the catch (ValidationException ex) where you can decide what to do with the validation error
You have a class that it's whole purpose is to validate, So you could add a public method IsValidated
You could add much more with the class, for example have a list of all business rules it violates and return them through another method or property.
class ValidateInput
{
public bool IsValidated {get; private set}
public bool ValidateFinancialsInput(string Co)
{
string[] validCompany = { "BVV", "LWDO" };
this.IsValidated = validCompany.Contains(Co)
}
}
This class should only know about the validation process and should do nothing else.
You have a few options. It looks like you have buttons in your program so I would guess this is not a console application. If you want the application to completely stop you can use Application.Exit or check out Environment.Exit https://msdn.microsoft.com/en-us/library/system.environment.exit(v=vs.110).aspx
However, I would suggest using exceptions so you do not terminate your entire program:
try
{
var CompanyVar = comboBox1.Text;
ValidateInput vi = new ValidateInput();
vi.ValidateFinancialsInput(CompanyVar);
//the rest of my code for the application is here
//the rest ...
//the rest...
}
catch (ValidationException ex)
{
MessageBox.Show(ex.Message);
}
}
public void ValidateFinancialsInput(string Co)
{
string[] validCompany = { "BVV", "LWDO" };
if (validCompany.Contains(Co) == false)
{
throw new ValidationException("You have entered an invalid company.");
}
}

Best way to pass data to a DataGridView form from another non-form class

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.

OpenFileDialog filename serialization

In writing a program where I need to serialize an AppSettings object which consists of several properties including one that will be used to store a last used filename, I have found that the FileName property is placed into my object (by assignment) but it does not serialize to the xml file. No exceptions are thrown and no data is written.
But conversely, if I programmtically modify the object
tc.TheDataFile = "c:\\Documents And Settings\\SomeUser\\Sample\\a test file.txt";
instead of
tc.TheDataFile = theDialog.FileName;
That will work. Can someone please provide some insight with regard to what I am missing?
Here is a simple version of the program that is directly related to the problem.
The test class which will theoretically hold the AppSettings ---
[Serializable()]
public class TestClass
{
private string m_TheDataFile;
private bool m_UseLastKnownDataFile = true;
public bool UseLastKnownDataFile
{
get
{
return m_UseLastKnownDataFile;
}
set
{
m_UseLastKnownDataFile = value;
}
}
public string TheDataFile
{
get
{
return m_TheDataFile;
}
set
{
m_TheDataFile = value;
}
}
}
public class TestClassHelper
{
public static TestClass Load()
{
XmlSerializer serializer = new XmlSerializer(typeof(TestClass));
TestClass retVal;
TextReader reader = null;
bool fileNotFound = false; ;
try
{
reader = new StreamReader("TestClassConfig.xml");
}
catch (FileNotFoundException)
{
fileNotFound = true;
}
if (fileNotFound)
{
retVal = new TestClass();
}
else
{
retVal = (TestClass)serializer.Deserialize(reader);
reader.Close();
}
return retVal;
}
public static void Save(TestClass settings)
{
XmlSerializer serializer = new XmlSerializer(typeof(TestClass));
TextWriter writer = new StreamWriter("TestClassConfig.xml");
serializer.Serialize(writer, settings);
writer.Close();
}
}
And here is the form which will prompt the user for a filename. In this test, there is a form with one button.
public partial class Form1 : Form
{
TestClass tc = null;
public Form1()
{
InitializeComponent();
tc = TestClassHelper.Load();
}
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog theDialog = new OpenFileDialog();
string fileName = string.Empty;
theDialog.CheckFileExists = true;
theDialog.CheckPathExists = true;
theDialog.Multiselect = false;
theDialog.FileName = string.Empty;
if (theDialog.ShowDialog() == DialogResult.OK)
{
tc.TheDataFile = theDialog.FileName;
}
else
{
tc.TheDataFile = string.Empty;
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
TestClassHelper.Save(tc);
}
}
Edit To Add:
I'm using Microsoft Visual Studio 2005 Team Edition w/Dot Net 2.0.50727 SP1, with no options to upgrade the development environment.
Solution
I'm not exactly sure why this happens, but the OpenFileDialog control must change the current operating directory of the program. When the object is deserialized to the xml file, it no longer writes where it originally opened. Rather it is created in the new directory.
I corrected the problem by making the XML read and write location more specific.
The problem is that you are setting tc.TheDataFile = fileName; after the if block, but you never assign anything to fileName except when you initialize it to string.Empty. One fix would be:
if (theDialog.ShowDialog() == DialogResult.OK)
{
fileName = theDialog.FileName;
}
// record last used data file
tc.TheDataFile = fileName;
or just
if (theDialog.ShowDialog() == DialogResult.OK)
{
tc.TheDataFile = theDialog.FileName;
}
Note that running your test in the debugger and "watch"ing the variables would have made the problem fairly easy to spot.

StreamWriter disposed when accessing method

I'm facing a problem where my declared StreamWriter gets disposed when I try to use a method to write on my log file. Everything is working as expected, except when I run AttachPink or AttachBlue, from another class. Then the StreamWriter is disposed and I get a nullPointerException
class Logs : IDisposable
{
//other declarations
private StreamWriter HistoryWriter;
private int ReportInterval = 0;
public void NewHistory()
{
HistoryWriter = new StreamWriter(HistoryLocation + HistoryName + HistoryExtension);
PrepareHistory();
}
private void PrepareHistory()
{
HistoryWriter.WriteLine("<html><body bgcolor='#000000'>");
/*
* Insert initial HTML tags
*/
}
public void SendHistory()
{
HistoryWriter.WriteLine("</body></html>");
/*
* Final HTML tags
*/
HistoryWriter.Close();
if (ReportInterval > 0)
{
/*
* Upload File
*/
}
else
{
Debug.WriteLine("ERROR: Report Interval for History has not been set");
}
NewHistory();
}
public void AttachPink(String message, StreamWriter writer)
{
writer.Write(
"<font color='DA1BE0'>"
+ message
+ "</font>");
}
public void AttachBlue(String message, StreamWriter writer)
{
writer.Write(
"<font color='0C93ED'>"
+ message
+ "</font>");
}
public StreamWriter getHistoryWriter()
{
return HistoryWriter;
}
public void SetHistoryInterval(int interval)
{
ReportInterval = interval;
}
public void Dispose()
{
if (HistoryWriter != null)
{
HistoryWriter.Close();
HistoryWriter.Dispose();
HistoryWriter = null;
}
}
}
To use the methods I simply declare an instance of Logs class inside another class, like so:
class UsingLogs
{
Logs logs = new Logs();
logs.NewHistory();
logs.AttachBlue("my message", logs.getHistoryWriter());
}
I don't know how should I go for preserving classes variables state when accessing multiple methods.
I guess what you are looking for is the Singleton Pattern (http://en.wikipedia.org/wiki/Singleton_pattern)
a simple implementation of mine which you can reuse every time you need a singleton
public class Singleton<T> where T : class, new()
{
private static object sync = null;
private static volatile T i;
protected Singleton() { }
public static T I
{
get
{
if (i == null)
lock (sync)
if (i == null)
i = new T();
return i;
}
}
}
You can implement your Log class like this:
class Logs : Singleton<Logs>
{
... your code goes here
}
In your code, when you want to use the Logs class, you simply use:
Logs.I.AttachBlue(...);
Hope this helps :)

Categories

Resources