UI Not Loading When Using While In Foreach Loop - c#

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");
}
}

Related

C# how to place txt file from openFileDialog into array scriptFile[][] by line#, and line string content

I am trying to create a tool in C#. The tool is to allow a user the ability to see some foreign language text line-by-line, and enter in their human translation in a text box below, submit, and eventually save to a new text file.
I am trying to open a .txt file with openFileDialog, then send line-by-line through a for loop that will add into a two dimensional array, 4 things:
Things we need:
Array scriptFile[][]
scriptFile[X][0] = Int holding the Line number
scriptFile[X][1] = First line piece
scriptFile[X][2] = Untranslated Text
scriptFile[X][3] = Translated Text input
The first part of the Array is the line number in an Integer.
The Second and third pieces are 2 pieces of text separated by a TAB.
Example Text File:
Dog 슈퍼 지방입니다.
cat 일요일에 빨간색입니다.
Elephant 적의 피로 위안을 찾는다.
Mouse 그의 백성의 죽음을 복수하기 위해 싸우십시오.
racoon 즉시 의료 지원이 필요합니다.
Which then:
So array:
scriptFile[0][0] = 1
scriptFile[0][1] = Dog
scriptFile[0][2] = 슈퍼 지방입니다.
scriptFile[0][3] = "" (Later input as human translation)
If I can crack this, then everything else will just fall into place in no time. I'm continuing to look for solutions, but my knowledge of C# is limited since I'm mainly a Java/PHP guy :/
So far I have the lien count down, and continuing to work on sorting everything into an array. So far what I kind of have:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.continueButton.Click += new System.EventHandler(this.continueButton_Click);
}
private void continueButton_Click(object sender, EventArgs e)
{
if (openFile.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
System.IO.StreamReader sr = new System.IO.StreamReader(openFile.FileName);
var lineCount = File.ReadLines(openFile.FileName).Count();
MessageBox.Show(lineCount.ToString());
sr.Close();
}
}
private void Form1_Load(object sender, EventArgs e)
{
openFile.Filter = "Text files (.txt)|*.txt";
}
}
There is probably no learning effect but i figured it out.
NOTE This is very raw code. There is no exception handling.
using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace TextArrayManipulation
{
public partial class Form1 : Form
{
private TaskCompletionSource<string> _translationSubmittedSource = new TaskCompletionSource<string>();
private string[,] _result;
public Form1()
{
InitializeComponent();
}
private async void buttonOpen_Click(object sender, EventArgs e)
{
using (var ofd = new OpenFileDialog())
{
if (ofd.ShowDialog() != DialogResult.OK) return;
_result = new string[File.ReadLines(openFile.FileName).Count(), 4];
using (var streamReader = new StreamReader(ofd.FileName))
{
var line = string.Empty;
var lineCount = 0;
while (line != null)
{
line = streamReader.ReadLine();
if (string.IsNullOrWhiteSpace(line)) continue;
// update GUI
textBoxLine.Text = line;
labelLineNumber.Text = lineCount.ToString();
// wait for user to enter a translation
var translation = await _translationSubmittedSource.Task;
// split line at tabstop
var parts = line.Split('\t');
// populate result
_result[lineCount, 0] = lineCount.ToString();
_result[lineCount, 1] = parts[0];
_result[lineCount, 2] = parts[1];
_result[lineCount, 3] = translation;
// reset soruce
_translationSubmittedSource = new TaskCompletionSource<string>();
// clear TextBox
textBoxTranslation.Clear();
// increase line count
lineCount++;
}
}
// proceede as you wish...
}
}
private void buttonSubmit_Click(object sender, EventArgs e)
{
_translationSubmittedSource.TrySetResult(textBoxTranslation.Text);
}
}
}
I would suggest making your translations a class, in the long run this will serve you much better. A very basic class implementation might look something like this:
public class Translation
{
public int Id { get; set; }
public string Text { get; set; }
public string TranslatedText { get; set; }
public Translation()
{
}
public IEnumerable<Translation> ReadTranslationFile(string TranslationFileName)
{
var translations = new List<Translation>();
//implement reading in text file
return translations;
}
public void WriteTranslationFile(string TranslationFileName, List<Translation> Translations)
{
//implement writing file
}
}
Well, you've received already two full answers, but i'll post my take anyways, maybe it will be helpful in figuring out the right solution.
public void Main()
{
List<LineOfText> lines = ReadTextFile("file.txt");
// Use resulting list like this
if (lines.Count > 0)
{
foreach (var line in lines)
{
Console.WriteLine($"[{line.LineNumber}] {line.FirstLinePiece}\t{line.UntranslatedText}");
}
}
}
class LineOfText
{
public int LineNumber { get; set; }
public string FirstLinePiece { get; set; }
public string UntranslatedText { get; set; }
public string TranslatedText { get; set; }
}
private List<LineOfText> ReadTextFile(string filePath)
{
List<LineOfText> array = new List<LineOfText>();
using (StreamReader sr = new StreamReader(filePath))
{
// Read entire file and split into lines by new line or carriage return symbol
string[] lines = sr.ReadToEnd().Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
// Parse each line and add to the list
for (int i = 0; i < lines.Length; i++)
{
int tabIndex = lines[i].IndexOf('\t');
string firstPiece = lines[i].Substring(0, tabIndex);
string restOfLine = lines[i].Substring(tabIndex + 1);
array.Add(new LineOfText()
{
LineNumber = i,
FirstLinePiece = firstPiece,
UntranslatedText = restOfLine
});
}
}
return array;
}

how to do a multithreaded text search using background worker and display the entire line in a listview in c#

So, I have a win form where I have to search for a string in a text file and display the line number and the entire line if I found the string. The search has to be multithreaded and all the line numbers and the lines must be on a listview. For example if the word "language" is in line number 60 , the listview must display:
60 "the line has the word language"
I have used the background worker in this regard but I am not being able to display the correct line number and the lines. Firstly, one line is being displayed multiple times and secondly, the line number is always coming to be 0. However, when I output the result in Console, the result is correct. I think I am making some error in putting the result into the listview.
Here' s my main form.cs
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// private bool start_cancel;
bool bln = true;
private void StartCancelbtn_Click(object sender, EventArgs e)
{
if (bln)
text2();
else
text1();
bln = !bln;
}
private void text1()
{
StartCancelbtn.Text = "Start";
this.backgroundWorker1.CancelAsync();
}
private void text2()
{
StartCancelbtn.Text = "Cancel";
StartThread();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
System.ComponentModel.BackgroundWorker worker;
worker = (System.ComponentModel.BackgroundWorker)sender;
// Get the Words object and call the main method.
main_work WC = (main_work)e.Argument;
WC.CountWords(worker, e);
if (worker.CancellationPending)
{
e.Cancel = true;
// break;
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
main_work.ReportState state =
(main_work.ReportState)e.UserState;
ListViewItem l1 = new ListViewItem();
l1.Text = state.LinesCounted.ToString();
l1.SubItems.Add(state.line);
listView1.Items.Add(l1);
}
private void backgroundWorker1_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
MessageBox.Show("Error: " + e.Error.Message);
else if (e.Cancelled)
MessageBox.Show("Word counting canceled.");
else
MessageBox.Show("Finished counting words.");
}
private void StartThread()
{
main_work WC = new main_work();
WC.CompareString = this.searchtext.Text;
WC.SourceFile = this.filenametextbox.Text;
// Start the asynchronous operation.
backgroundWorker1.RunWorkerAsync(WC);
}
private void browsebtn_Click(object sender, EventArgs e)
{
using (OpenFileDialog brw = new OpenFileDialog())
{
if (brw.ShowDialog() == DialogResult.OK)
{
using (StreamReader sr = new StreamReader(brw.FileName))
{
filenametextbox.Text = brw.FileName.ToString();
}
}
}
}
}
}
Here is my main_work class where the actual comparison is happening:
class main_work
{
public class ReportState
{
public int LinesCounted;
public string line;
}
Queue q = new Queue();
public string SourceFile;
public string CompareString;
public string line2 ;
public int linenumber=0;
public int linenumber1 = 0;
int LinesCounted1;
// public string line2;
public void CountWords(
System.ComponentModel.BackgroundWorker worker,
System.ComponentModel.DoWorkEventArgs e)
{
// Initialize the variables.
ReportState state = new ReportState();
string line1 = "";
int elapsedTime = 1;
DateTime lastReportDateTime = DateTime.Now;
if (CompareString == null ||
CompareString == System.String.Empty)
{
MessageBox.Show("Please Enter a string to be searched");
}
else
{
// Open a new stream.
using (System.IO.StreamReader myStream = new System.IO.StreamReader(SourceFile))
{
// Process lines while there are lines remaining in the file.
while (!myStream.EndOfStream)
{
if (worker.CancellationPending)
{
e.Cancel = true;
// break;
}
else
{
line1 = myStream.ReadLine();
line2 = (CountInString(line1, CompareString));
LinesCounted1 = (linenumbercount(line1, CompareString, linenumber1));
// Raise an event so the form can monitor progress.
int compare = DateTime.Compare(
DateTime.Now, lastReportDateTime.AddSeconds(elapsedTime));
if (compare > 0)
{
state.LinesCounted = LinesCounted1;
state.line = line2;
worker.ReportProgress(0, state);
lastReportDateTime = DateTime.Now;
}
System.Threading.Thread.Sleep(1);
}
}
// Report the final count values.
state.LinesCounted = LinesCounted1;
state.line = line1;
worker.ReportProgress(0, state);
lastReportDateTime = DateTime.Now;
}
}
}
private string CountInString(
string SourceString,
string CompareString)
{
if (SourceString.Contains(CompareString))
{
line2 = SourceString;
Console.WriteLine(SourceString);
}
return line2;
}
private int linenumbercount(
string SourceString,
string CompareString,
int linenumber)
{
// Lines = 0;
if (SourceString == null)
{
return 0;
}
if (SourceString.Contains(CompareString))
{
Console.WriteLine(linenumber);
}
linenumber++;
return linenumber;
}
}
Any feedback will be helpful. Please let me know what I am doing wrong and where is it that I am making a mistake as I am new to background worker and multithreading. Thanks.

Design solution for working with multiple instantiations at the same time

I don't know if my title is correct. But here's what I want to know.
I have a Download class that returns certain events and has a couple of methods. Each instance of Download class can download a single file. And all those events and methods are related to the file being downloaded.
As it's a multi file downloader, multiple instantiations are required when more than a single file needs to be downloaded.
Each download has a download id, but that is not supplied to the Download class, to keep it independent from the other classes.
Now getting all the info from each instance of the file download and being able to control a single download, is the problem. How do I know which download is which?
Any solutions? Or design patterns you could recommend? I've hit a roadblock.
Download class:
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Threading;
namespace Mackerel_Download_Manager
{
public class Download
{
public event EventHandler<DownloadStatusChangedEventArgs> ResumablityChanged;
public event EventHandler<DownloadProgressChangedEventArgs> ProgressChanged;
public event EventHandler Completed;
public bool stop = true; // by default stop is true
public bool paused = false;
SemaphoreSlim pauseLock = new SemaphoreSlim(1);
string filename;
public void DownloadFile(Uri DownloadLink, string Path)
{
filename = System.IO.Path.GetFileName(Path);
stop = false; // always set this bool to false, everytime this method is called
var fileInfo = new FileInfo(Path);
long existingLength = 0;
if (fileInfo.Exists)
existingLength = fileInfo.Length;
var request = (HttpWebRequest)HttpWebRequest.Create(DownloadLink);
request.Proxy = null;
request.AddRange(existingLength);
try
{
using (var response = (HttpWebResponse)request.GetResponse())
{
long fileSize = existingLength + response.ContentLength; //response.ContentLength gives me the size that is remaining to be downloaded
bool downloadResumable; // need it for not sending any progress
if ((int)response.StatusCode == 206) //same as: response.StatusCode == HttpStatusCode.PartialContent
{
//Console.WriteLine("Resumable");
downloadResumable = true;
}
else // sometimes a server that supports partial content will lose its ability to send partial content(weird behavior) and thus the download will lose its resumability
{
if (existingLength > 0)
{
if (ResumeUnsupportedWarning() == false) // warn and ask for confirmation to continue if the half downloaded file is unresumable
{
return;
}
}
existingLength = 0;
downloadResumable = false;
}
OnResumabilityChanged(new DownloadStatusChangedEventArgs(downloadResumable));
using (var saveFileStream = fileInfo.Open(downloadResumable ? FileMode.Append : FileMode.Create, FileAccess.Write))
using (var stream = response.GetResponseStream())
{
byte[] downBuffer = new byte[4096];
int byteSize = 0;
long totalReceived = byteSize + existingLength;
var sw = Stopwatch.StartNew();
while (!stop && (byteSize = stream.Read(downBuffer, 0, downBuffer.Length)) > 0)
{
saveFileStream.Write(downBuffer, 0, byteSize);
totalReceived += byteSize;
float currentSpeed = totalReceived / (float)sw.Elapsed.TotalSeconds;
OnProgressChanged(new DownloadProgressChangedEventArgs(totalReceived, fileSize, (long)currentSpeed));
pauseLock.Wait();
pauseLock.Release();
}
sw.Stop();
}
}
if (!stop) OnCompleted(EventArgs.Empty);
}
catch (WebException e)
{
System.Windows.MessageBox.Show(e.Message, filename);
}
}
public void pause()
{
if (!paused)
{
paused = true;
// Note this cannot block for more than a moment
// since the download thread doesn't keep the lock held
pauseLock.Wait();
}
}
public void unpause()
{
if (paused)
{
paused = false;
pauseLock.Release();
}
}
public void StopDownload()
{
stop = true;
this.unpause(); // stop waiting on lock if needed
}
public bool ResumeUnsupportedWarning()
{
var messageBoxResult = System.Windows.MessageBox.Show("When trying to resume the download , Mackerel got a response from the server that it doesn't support resuming the download. It's possible that it's a temporary error of the server, and you will be able to resume the file at a later time, but at this time Mackerel can download this file from the beginning.\n\nDo you want to download this file from the beginning?", filename, System.Windows.MessageBoxButton.YesNo);
if (messageBoxResult == System.Windows.MessageBoxResult.Yes)
{
return true;
}
else
{
return false;
}
}
protected virtual void OnResumabilityChanged(DownloadStatusChangedEventArgs e)
{
var handler = ResumablityChanged;
if (handler != null)
{
handler(this, e);
}
}
protected virtual void OnProgressChanged(DownloadProgressChangedEventArgs e)
{
var handler = ProgressChanged;
if (handler != null)
{
handler(this, e);
}
}
protected virtual void OnCompleted(EventArgs e)
{
var handler = Completed;
if (handler != null)
{
handler(this, e);
}
}
}
public class DownloadStatusChangedEventArgs : EventArgs
{
public DownloadStatusChangedEventArgs(bool canResume)
{
ResumeSupported = canResume;
}
public bool ResumeSupported { get; private set; }
}
public class DownloadProgressChangedEventArgs : EventArgs
{
public DownloadProgressChangedEventArgs(long totalReceived, long fileSize, long currentSpeed)
{
BytesReceived = totalReceived;
TotalBytesToReceive = fileSize;
CurrentSpeed = currentSpeed;
}
public long BytesReceived { get; private set; }
public long TotalBytesToReceive { get; private set; }
public float ProgressPercentage
{
get
{
return ((float)BytesReceived / (float)TotalBytesToReceive) * 100;
}
}
public float CurrentSpeed { get; private set; } // in bytes
public TimeSpan TimeLeft
{
get
{
var bytesRemainingtoBeReceived = TotalBytesToReceive - BytesReceived;
return TimeSpan.FromSeconds(bytesRemainingtoBeReceived / CurrentSpeed);
}
}
}
}
Download class is instantiated inside a Mackerel class, that starts the download for the given downloads.
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows;
namespace Mackerel_Download_Manager
{
public static class Mackerel
{
//Main Menu functions
public static void ResumeDownload(string[] DownloadIDs)
{
foreach (var DownloadID in DownloadIDs)
{
var itemToResume = Downloads.DownloadEntries.Where(download => download.DownloadID == DownloadID).FirstOrDefault();
if (itemToResume.Running == false)
{
itemToResume.Running = true;
var download = new Download();
download.DownloadFile(itemToResume.DownloadLink, itemToResume.SaveTo);
var window = new Dialogs.DownloadProgress(itemToResume);
window.Show();
double progress = 0;
itemToResume.Status = string.Format("{0:0.00}%", progress);
Downloads.DownloadEntries.CollectionChanged += delegate
{
if (!itemToResume.Running) window.Close();
};
}
}
}
public static void StopDownload(string[] DownloadIDs)
{
foreach (var DownloadID in DownloadIDs)
{
var itemToStop = Downloads.DownloadEntries.Where(download => download.DownloadID == DownloadID).FirstOrDefault();
if (itemToStop.Running == true)
itemToStop.Running = false;
}
}
public static void StopAllDownloads()
{
foreach (var itemToStop in Downloads.DownloadEntries.Where(download => download.Running == true))
itemToStop.Running = false;
}
public static void RemoveDownload(string[] DownloadIDs) // this method is able to delete multiple downloads
{
foreach (var DownloadID in DownloadIDs)
{
// delete from the download list
var selectedDownload = Downloads.DownloadEntries.Where(download => download.DownloadID == DownloadID).FirstOrDefault();
var selectedDownloadIndex = Downloads.DownloadEntries.IndexOf(selectedDownload);
Downloads.DownloadEntries.RemoveAt(selectedDownloadIndex);
//delete from the harddrive
if (File.Exists(selectedDownload.SaveTo))
File.Delete(selectedDownload.SaveTo);
}
Downloads.Serialize(); // save current state of object
}
public static void RemoveCompletedDownloads() // this method just removes all completed downloads from Mackerel's download list (it doesn't delete them from the hard drive)
{
foreach (var itemToRemove in Downloads.DownloadEntries.Where(download => download.Status == "Complete").ToList())
{
Downloads.DownloadEntries.Remove(itemToRemove);
}
}
// Context Menu
public static void OpenDownloadProperties(string DownloadID) // Open "Download Properties" for the given download ID
{
var DownloadProperties = new Dialogs.Context_Menu.DownloadProperties(DownloadID);
DownloadProperties.Owner = Application.Current.MainWindow; // so that this dialog centers to its parent window, as its window is set to WindowStartupLocation="CenterOwner"
DownloadProperties.ShowDialog();
}
}
}
Full source code is here: https://github.com/Expenzor/mackerel-download-manager
Sounds like your making the download itself an object but are using "downloader" as the name instead. I would maybe suggest an array of downloaded objects or similar. The downloader class can have a method which creates a new object - perhaps a download object. Using an array or linked list etc will give you the opportunity to address the object and call them independently - know which is which.
Posting your code would help as well.

to get the number of files recursively

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.

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

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)
{
...
}
}

Categories

Resources