Real Time Counter in C# using Windows Form - c#

How can I do a counter in my Windows Form for count row many rows was read ?
When I execute my Windows Form this counter are shown just when the application processed every data.
Sample Code
public Form1()
{
InitializeComponent();
setMessage(string.Empty, this.lblErro);
}
private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i <= xmlnode.Count - 1; i++)
{
int cont = i;
ThreadPool.QueueUserWorkItem(_ =>
{
setMessage(++cont + " of " + xmlnode.Count, this.lblCounter);
});
}
void setMessage(string message, Label lbl)
{
if (InvokeRequired)
{
Invoke((MethodInvoker)(() => setMessage(message, lbl)));
}
else
{
lbl.Text = message;
}
}
}
I tryied the code above but without success. Still shown the message when the app processed all the data

You need to run this loop:
for (int i = 0; i <= xmlnode.Count - 1; i++)
{
...
}
off of the main UI thread. There are a number of ways to accomplish this, but I prefer the BackgroundWorker for whatever reason. You could do it like this:
BackgroundWorker _worker = new BackgroundWorker();
and then in the ctor:
_worker.DoWork += (s, e) =>
{
// place the entire for loop in here
}
and now when you're ready to run it then just do this:
_worker.RunWorkerAsync();

Try putting the loop inside:
ThreadPool.QueueUserWorkItem(_ => {
for (int i = 0; i <= xmlnode.Count - 1; i++)
{
int cont = i;
setMessage(++cont + " of " + xmlnode.Count, this.lblCounter);
}
});

Related

Display only Even numbers in C#, using Windows Forms

I think this is a very easy answer and I understand that you enter something like this get an even number:
if (i % 2 == 0)
But I am just struggling to figure out how to slot it into my current code that I have here...
I have a form like so:
I am double clicking the 'Show Numbers' button
And I want the user to click the show numbers button and it only spits out even numbers, regardless if the box is checked or not.
namespace CHECK_BOXES
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
textBox1.Text = "";
if (checkBox1.Checked)
{
for (int i = 1; i <= 20; i++)
{
textBox1.Text += i.ToString() + "\r\n";
}
}
else
{
for (int i = 20; i >= 1; i--)
{
textBox1.Text += i.ToString() + "\r\n";
}
}
}
}
}
Would appreciate any help.
Thank you
Try with this function:
public bool IsEven(int value)
{
return value % 2 == 0;
}
and then update your for each loop with the following statement:
for (int i = 1; i <= 20; i++)
{
if (IsEven(i))
{
textBox1.Text += i.ToString() + "\r\n";
}
}
Or just easily increment i in for loop with 2.
Just do "double"-steps.
for (int i = 0; i <= 20; i += 2) { // <- pay attention, i will be incremented by 2
textBox1.Text += i.ToString() + "\r\n";
}
could be one line with Linq
textBox1.Text = string.Join("\r\n", Enumerable.Range(0, 20)
.Where((_, index) => index % 2 == 0).Select(x => x));

How to avoid the control gets freeze while updating the datasource at runtime?

I am working in WinForms application and used DataGridView control in my application. Initially,i have loaded the 10000 rows and 50 columns in it. My scenario is that updating the datasource at particular time interval(using Timer).
Problem: The grid has been frozen/gang when performing the action(cell_click, scrolling, etc) while updating the datasource.
How to resolve this issue? Is there any work-around? Please suggest me your ideas.
Here is my code so far:
private void timer1_Tick(object sender, EventArgs e)
{
//try
{
timer.Stop();
for (int i = 0; i < 10000; i++)
{
var row = r.Next() % 10000;
for (int col = 1; col < 10; col++)
{
var colNum = r.Next() % 55;
if (table != null)
table.Rows[row][colNum] = "hi";// r.Next().ToString();
}
}
table.AcceptChanges();
timer.Start();
}
}
Here is an sample output:
[https://drive.google.com/open?id=0B9MOGv1FOt-TQ1BNZWtnRktxeXc]
Thanks.
One of the solutions is to call Application.DoEvents() during such long running operation. Here is the sample
private void timer1_Tick(object sender, EventArgs e)
{
//try
{
timer.Stop();
for (int i = 0; i < 10000; i++)
{
var row = r.Next() % 10000;
for (int col = 1; col < 10; col++)
{
var colNum = r.Next() % 55;
if (table != null)
table.Rows[row][colNum] = "hi";// r.Next().ToString();
}
Application.DoEvents(); //add this line
}
table.AcceptChanges();
timer.Start();
}
}
Another solution is to move your long running task to a separate thread.
Try to use a BackgrounWorker.
BackgroundWorker is a helper class in the System.ComponentModel
namespace for managing a worker thread. It can be considered a
general-purpose implementation of the EAP(The Event-Based Asynchronous Pattern), and provides the following
features:
A cooperative cancellation model
The ability to safely update WPF or Windows Forms controls when the worker completes
Forwarding of exceptions to the completion event
A protocol for reporting progress
An implementation of IComponent allowing it to be sited in Visual Studio’s designer
Bellow you can find an example, please adapt it to your Timer:
class Program
{
static BackgroundWorker _bw = new BackgroundWorker();
static void Main()
{
_bw.DoWork += bw_DoWork;
_bw.RunWorkerAsync ("Message to worker");
Console.ReadLine();
}
static void bw_DoWork (object sender, DoWorkEventArgs e)
{
// This is called on the worker thread
Console.WriteLine (e.Argument); // writes "Message to worker"
// Perform time-consuming task...
//update your grid
for (int i = 0; i < 10000; i++)
{
var row = r.Next() % 10000;
for (int col = 1; col < 10; col++)
{
var colNum = r.Next() % 55;
if (table != null)
table.Rows[row][colNum] = "hi";r.Next().ToString();
}
}
table.AcceptChanges();
}
}

Dynamic Label Text within a for loop

I made a simple WF in C# in an attempt to change the label dynamically.
However, when I run this code, there is no visible change, until after the code has run, and then it changes to "Processing 9" 0-8 are not ever shown. Is it because it is within the loop?
private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < 10; i++)
{
label9.Text = "Processing " + i.ToString();
Thread.Sleep(1000);
}
}
EDIT: X-Tech's code worked but when I tried to incorporate it into my code, I get the following threading issue. I am trying to dynamically change the label.text in the loop while the progress bar is rocking:
An exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll but was not handled in user code
Additional information: Cross-thread operation not valid: Control 'progressBar1' accessed from a thread other than the thread it was created on.
If there is a handler for this exception, the program may be safely continued
I am not sure how to attack this since I am not super familiar with Task.Factory.StartNew() and Invoke statements.
EDIT 2: Adapted Code:
Task.Factory.StartNew(() =>
{
for (int i = 0; i < lstFilesToZip.Items.Count; i++)
{
zipArray[i] = lstFilesToZip.Items[i].ToString();
// Report progress.
ExecuteSecure(() => label9.Text = "Processing :" + Path.GetFileNameWithoutExtension(lstFilesToZip.Items[i].ToString()));
ExecuteSecure(() => progressBar1.PerformStep());
string zipFileName = Path.GetFileName(zipArray[i]);
string newFolder = txtDestinationFolder.Text + "\\" + Path.GetFileNameWithoutExtension(zipArray[i]);
//check to see if a directory with the file name for the zip file already exists, if not, it will create it
if (Directory.Exists(newFolder) == false)
{
DirectoryInfo newPath = Directory.CreateDirectory(newFolder);
if (lstCommonFiles.Items.Count > 0)
{
//copies each file in the common file list to each new folder created, the boolean indicates that it will overwrite existing files (true) or won't (false)
for (int k = 0; k < lstCommonFiles.Items.Count; k++)
{
File.Copy(lstCommonFiles.Items[k].ToString(), (newFolder + "\\" + Path.GetFileName(commonArray[k])), true);
}
}
//adds the zip file into the folder as well
File.Copy(zipArray[i], (newFolder + "\\" + zipFileName), true);
}
}
if (txtCommonFiles.Text.Length <= 0)
{
string result = "There are no common files selected, would you still like to proceed?";
DialogResult result1 = MessageBox.Show(result, "Common Files Missing", MessageBoxButtons.YesNo);
if (result1 == DialogResult.No)
{
return;
}
}
string[] dirs = Directory.GetDirectories(txtDestinationFolder.Text);
// Grabs the folders in the newly created directory
foreach (string dir in dirs)
lstDestinationFinal.Items.Add(dir);
//send sample file contents to preview window
string[] sampleFiles = Directory.GetFiles(lstDestinationFinal.Items[0].ToString());
//grabs the files
foreach (string zipFiles in sampleFiles)
lstSampleFile.Items.Add(zipFiles);
ExecuteSecure(() =>tabControl1.SelectedTab = tabPage2);
});
}
And the added Method:
private void ExecuteSecure(Action action)
{
if (InvokeRequired)
{
Invoke(new MethodInvoker(() => action()));
}
else
{
action();
}
}
Try this
Task.Factory.StartNew(() =>
{
for (int i = 0; i < 10; i++)
{
Invoke(new MethodInvoker(() => label9.Text = "Processing " + i.ToString()));
Thread.Sleep(1000);
}
});
EDIT:
Task.Factory.StartNew(() =>
{
for (int i = 0; i < 10; i++)
{
// Any GUI control which you want to use within thread,
// you need Invoke using GUI thread. I have declare a method below for this
//Now use this method as
ExecuteSecure(() => label9.Text = "Processing " + i);
ExecuteSecure(() => progressBar1.Value = i * 10);
//... other code etc.
Thread.Sleep(1000);
}
});
//---
private void ExecuteSecure(Action action)
{
if (InvokeRequired)
{
Invoke(new MethodInvoker(() => action()));
}
else
{
action();
}
}
Use a BackgroundWorker if you want your UI to be updated in real time, else all the work is done on the UI thread and it remains frozen until the work is over.
private void button1_Click(object sender, EventArgs e)
{
int limit = 10;
var bw = new BackgroundWorker();
bw.WorkerReportsProgress = true;
bw.DoWork += (s, ee) =>
{
for (int i = 0; i < limit; i++)
{
bw.ReportProgress(i);
Thread.Sleep(1000);
}
};
bw.ProgressChanged += (s, ee) => label9.Text = "Processing" + ee.ProgressPercentage.ToString();
bw.RunWorkerAsync();
}
Maybe try
private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < 10; i++)
{
label9.Text = "Processing " + i.ToString();
Thread.Sleep(1000);
Form1.Refresh();
}
}
Try this:
private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < 10; i++)
{
label9.Text = "Processing " + i.ToString();
Application.DoEvents();
Thread.Sleep(1000);
}
}

Using two for-loops

This is an easy question but I'm still learning this language.
How we can write program that has parameters so that if the the number is 5, it will write
*
**
***
****
*****
I can do this:
*
*
*
*
Using this:
private void button1_Click(object sender, EventArgs e)
{
string message = " ";
for (int count = 0; count < numericUpDown1.Value; count++)
{
for (int m = 0; m < numericUpDown1.Value; count)
{
message += "*" + "\r\n";
}
}
}
I think I need the second for-loop, but I'm not sure what to do next.
if that's not a conceptual homework it would be much easier to solve this way:
for(int i=1; i<=n; i++)
Console.WriteLine(new string('*',i));
You need two loops (see note).
First (a) counts from 1 to 5.
Second (b) counts from 1 to a and adds a "*" each time.
private void button1_Click(object sender, EventArgs e)
{
string message = " ";
for (int count = 0; count < numericUpDown1.Value; count++)
{
for (int m = 0; m < count; m++)
{
message += "*";
}
message += "\r\n"
}
}
Note You can do it with one for loop. But personally I think the two loop version is clearer.
private void button1_Click(object sender, EventArgs e)
{
string line = "";
string message = " ";
for (int count = 0; count < numericUpDown1.Value; count++)
{
line += "*";
message += "\r\n" + line;
}
}
Try this :
private void button1_Click(object sender, EventArgs e)
{
string message = "";
for (int count = 0; count < numericUpDown1.Value; count++)
{
for (int m = 0; m <=count ; m++)
{
message += "*" ;
}
message += "\r\n";
}
}
Yo do not need two for-loops, try this instead
private void button1_Click(object sender, EventArgs e)
{
string message = "";
for (int count = 1; count < numericUpDown1.Value + 1; count++)
{
message += "".PadLeft(count,'*') + Environment.NewLine;
}
}
Try this, just another way to do it for learning:
private static void PrintStars(int num)
{
for (int i = 1; i <= num; i++)
{
for (int j = 1; j <= i; j++)
{
Console.Write("*");
}
Console.WriteLine();
}
}

Multithreading and ProgressBar

Need to make an multithreading application, which performs some activities and shows progress of all work in ProgressBar. Here is the code. Only thread named "thread - 0" makes all work. I need to distribute work between all threads.
public partial class Form1 : Form
{
const float maxWorkedValue = 10;
const int threadsCount = 5;
float totalProgress;
int threadSleepTime = 1;
object locker = new object();
List<Thread> threads = new List<Thread>();
public Form1()
{
InitializeComponent();
prBar.Maximum = (int)maxWorkedValue;
prBar.Step = 1;
for (int i = 0; i < threadsCount; i++)
{
threads.Add(new Thread(BeginCalculate) { Name = "Thread - " + i.ToString() });
threads[i].Start();
}
}
void BeginCalculate()
{
for (int i = 0; i < maxWorkedValue; i++)
{
lock (locker)
{
float currentProgress = CalculateLongTask(i);
Update((currentProgress / maxWorkedValue) * 100, Thread.CurrentThread.Name);
Thread.Sleep(threadSleepTime);
}
}
}
float CalculateLongTask(int value)
{
for (int i=0; i<value;i++)
Thread.Sleep(threadSleepTime);
return totalProgress++;
}
void Update(float i, string threadName)
{
if (InvokeRequired)
{
BeginInvoke(new Action<float, string>(Update), new object[] { i, threadName });
return;
}
label1.Text = threadName;
prBar.Value = (int)i;
}
}
UPDATE2:
I've updated the code above. But it not resolved the problem. How to synchronize the variable "i" between different threads? An exception (progressbar.Max) is thrown. Why?
for (int i = 0; i < maxWorkedValue; i++)
{
lock (locker)
{
float currentProgress = CalculateLongTask(i);
Update((currentProgress / maxWorkedValue) * 100, Thread.CurrentThread.Name);
Thread.Sleep(15);
}
}
EDIT:
If I understood you correctly you want to execute a loop (i.e.for (int i = 0; i < maxWorkedValue; i++) ) concurrently among many threads.
This is extremely easier to accomplish using the Parallel extensions
1.
Here's your modified code:
public partial class Form1 : Form
{
const float maxWorkedValue = 100;
const int threadCount = 5;
float maxWorkedValue2 = 1;
Thread thread;
public Form1()
{
InitializeComponent();
prBar.Maximum = (int)maxWorkedValue;
prBar.Step = 1;
thread = new Thread(BeginCalculate) { Name = "Father thread" };
thread.Start();
}
void BeginCalculate()
{
Parallel.For(0, (int)maxWorkedValue,
(i) =>
{
float currentProgress = CalculateLongTask(i);
// here we are (probably) in a thread child
//of "Father thread" so let's use ManagedThreadId instead of the name...
Update((currentProgress / maxWorkedValue) * 100, Thread.CurrentThread.ManagedThreadId.ToString());
Thread.Sleep(2);
return;
});
}
float CalculateLongTask(int value)
{
for (int i = 0; i < value; i++)
Thread.Sleep(15);
return maxWorkedValue2++;
}
void Update(float i, string threadName)
{
if (InvokeRequired)
{
BeginInvoke(new Action<float, string>(Update), new object[] { i, threadName });
return;
}
label1.Text = threadName;
prBar.Value = Math.Min((int)i, 100);
}
}
1
If you're using .NET 4.0 Parallel extensions comes with the framework.
If you're using .NET 3.5, look at this Q&A to know how to use it.
Mostly, your locking scheme is broken:
void BeginCalculate() // main thread method
{
lock (locker)
{
.... // 1 thread at a time
}
}
All threads are run in sequence, you're not really multi-threading.
I can't comment on the rest except to say it doesn't look like something you should use for real.
You should probably outline what you really need to do, It won't be Sleep().

Categories