foreach (KeyValuePair<int, int[]> item in replay)// count should be more than 2
{
makeSelfMoves = replay[item.Key];
codeFile.ExecuteAll(makeSelfMoves[0], makeSelfMoves[1], makeSelfMoves[2], makeSelfMoves[3]);
PrintPieces(codeFile.PieceState());
// MessageBox.Show("rowStart: " + makeSelfMoves[0] + ". rowEnd: " + makeSelfMoves[2] + ". columnStart: " + makeSelfMoves[1] + ". columnEnd: " + makeSelfMoves[3] + "____a is: " + a);
}
i want to execute this whole iteration, that i responsible for a game replay, in 1 second intervals. i put a timer in my form and set it to 1 second (this should make the pieces to be moved at 1 second intervals). i made an event, and before the loop i put the statement, timer1.enabled=true. The iteration will reach the end in a quick manner.. how do you use a timer to set iteration to execute each second using the timer?
public void ReplayGame()
{
Class2.replayIsOn = true;
replay=serializeMeh.giveBackDictionary();
int[] makeSelfMoves=new int[4];
//Timer t = new Timer();
//t.Interval = 1000;
//t.Tick += timer1_Tick;
//t.Enabled = true;
//t.Start();
if (backgroundWorker1.IsBusy != true)
{
// Start the asynchronous operation.
backgroundWorker1.RunWorkerAsync();
}
//foreach (KeyValuePair<int, int[]> item in replay)// count should be more than 2
//{
// makeSelfMoves = replay[item.Key];
// codeFile.ExecuteAll(makeSelfMoves[0], makeSelfMoves[1], makeSelfMoves[2], makeSelfMoves[3]);
// PrintPieces(codeFile.PieceState());
// MessageBox.Show("rowStart: " + makeSelfMoves[0] + ". rowEnd: " + makeSelfMoves[2] + ". columnStart: " + makeSelfMoves[1] + ". columnEnd: " + makeSelfMoves[3] );
//}
}
The above method is activated if i want a replay.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
int[] makeSelfMoves = new int[4];
foreach (KeyValuePair<int, int[]> item in replay)// count should be more than 2
{
makeSelfMoves = replay[item.Key];// delivers an array of a single move location startrow,startcolumn,endrow,endcolun
codeFile.ExecuteAll(makeSelfMoves[0], makeSelfMoves[1], makeSelfMoves[2], makeSelfMoves[3]);
PrintPieces(codeFile.PieceState());// prints the code on the board
System.Threading.Thread.Sleep(1000);
}
}
it does the work, but the problem that i had is after the loop finishes, the pieces that existed disappear. is it because of the background worker, cause without it , i have no pieces disappear at the end of the process. The second time that i activate the method, it happens
Run it in a background thread and put Thread.Sleep(1000) in the loop.
This way it will be time based and not freeze your app.
We need to see more of your code, but it's pretty simple:
using System.Windows.Forms;
SomeMethod(...)
{
Timer t = new Timer();
t.Interval = 1000;
t.Tick += t_Tick;
t.Enabled = true;
t.Start();
}
void t_Tick(...)
{
foreach (KeyValuePair<int, int[]> item in replay)// count should be more than 2
{
makeSelfMoves = replay[item.Key];
codeFile.ExecuteAll(makeSelfMoves[0], makeSelfMoves[1], makeSelfMoves[2], makeSelfMoves[3]);
PrintPieces(codeFile.PieceState());
// MessageBox.Show("rowStart: " + makeSelfMoves[0] + ". rowEnd: " + makeSelfMoves[2] + ". columnStart: " + makeSelfMoves[1] + ". columnEnd: " + makeSelfMoves[3] + "____a is: " + a);
}
}
Personally, I would put this into a seperate thread and use Thread.sleep(). In combination with accessing GUI-elements, I would suggest a BackgroundWorker instead (see MSDN, easy to implement).
If you insist in using a timer, I would suggest you use the suggestion of 'Ed S.'. The timer could also be placed on your form, instead of creating it in code of course. Just what you prefer.
Related
I have two functions using a lock statement, where after some operations finished, I redirect the output in a .txt file. I have realised that their executions take a lot of time, resulting in blocking their operations and degrading the app's performance in general.
I was thinking that the high execution time could be due to the write operations into a file. What would be the most efficient way to reduce the execution time? Should I use another thread for the write operations, is it possible inside a lock without holding the lock?
A simplified version of my code is illustrated below:
StatsInformation statsInfo = new StatsInformation ();
List<int> lInt = new List<int>();
public void FunctionEnq(List<byte> lByte, int _int)
{
lock (OperationLock)
{
//Do some work here
lInt.Add(_int);
string result = "New Int " + _int + " size " + lInt.Count + " time " + DateTime.Now.ToString("hh:mm:ss.fff");
statsInfo.WriteStatsInFile(result);
}
}
public (List<byte> _outByte, int _time) FunctionDeq()
{
List<byte> _outByte = new List<byte> ();
int _time = -1;
lock (OperationLock)
{
//Do some work here
_outByte.Add(...);
int _int = lInt[0];
//do operations
_time = _int;
lInt.RemoveAt(0);
string result = "Get Int " + _int + " new size " + lInt.Count + " time " + DateTime.Now.ToString("hh:mm:ss.fff");
statsInfo.WriteStatsInFile(result);
}
return (_outByte, _time);
}
Iam a novice programmer who basically just started,im not sure what I should search for my issue,what I wanna do is making those points like Visual studio if someone already saw VS 2012-13 already installing , those points keep progressing and dissapearing ,hope some can help me out.
Have you tried with ascii and a label?
You can manage to wait for the process load and stuff so meanwhile you can show this:
label l1 = new label();
label.Location = new Point(X location, Y location) //Location despends on you
and then just add this in:
public Form1()
{
InitializeComponent();
label l1 = new label();
label.Location = new Point(X location, Y location) //Location despends on you
_load();
}
Create a timmer method:
private async void _load()
{
string[] n = { " ", " ", " ", " ", " ", " ", " ", " ", " ", " " };
while (true)
{
l1.Text = "• • • • •";
await Task.Delay(500);
for(int i=0; i<10; i++)
{
if (i < 4)
{
await Task.Delay(50);
l1.Text = "• • • •" + n[i] + "•";
}
else if(i >4 && i< 7)
{
await Task.Delay(100);
l1.Text = "• • • •" + n[i] + "•";
}
else
{
await Task.Delay(180);
l1.Text = "• • • •" + n[i] + "•";
}
}
}
}
You just have to use the head to guess how to make it look like the VS's one D:
Strings are funny :3
Don't do that. Microsoft is violating their own UI guidelines. (See #11 here].
Instead, indicate progress using a standard ProgressBar control. That's what it is for, and all your users already recognize its meaning.
The animation you indicate is most similar to the Marquee style of the standard progress bar.
I made this small program to test parallelization.
When I hit button1 several times it ends up with an IndexOutOfBounds exception. I guess this is because I run out of memory. Why do I get this with parallelization and not with a regular foreach(button2 click)?
private void button1_Click(object sender, EventArgs e)
{
var s = Stopwatch.StartNew();
int[] nums = new int[10000];
List<int> randoms = new List<int>();
Parallel.ForEach(nums, i =>
{
randoms.Add(new Random().Next());
});
s.Stop();
label1.Text = "Added " + randoms.Count() + " randoms in "
+ s.Elapsed.Milliseconds.ToString() + " milliseconds";
}
private void button2_Click(object sender, EventArgs e)
{
var s = Stopwatch.StartNew();
int[] nums = new int[10000];
List<int> randoms = new List<int>();
foreach (var i in nums)
{
randoms.Add(new Random().Next());
}
s.Stop();
label2.Text = "Added " + randoms.Count() + " randoms in "
+ s.Elapsed.Milliseconds.ToString() + " milliseconds";
}
You are modifying randoms in parallel. That is a bug because the list is not safe for concurrent adding.
Also, IndexOutOfBounds has nothing to do with out-of-memory. You can find out all of this by looking carefully at the exception: The message tells you it is not OOM. And the stack trace tells you in which line the error occured (it was in the Add-line, right?).
In your Parallel.ForEach code, you are concurrently modifying a List<int> which is not threadsafe.
The exception occurs when you try to add to the end of a List while the internal array is being resized in a different thread.
Instead you should use a concurrent collection like ConcurrentBag or ConcurrentQueue
I came up with the idea of making a label scroll a word to one side and then change the word and scroll back to the other like so
"ping "
" ping "
" ping "
" ping "
" ping "
" ping "
" ping "
" ping "
" ping "
" ping "
" ping "
" ping"
" pong"
" pong "
" pong "
" pong "
" pong "
" pong "
" pong "
" pong "
" pong "
" pong "
" pong "
"pong "
I want it to do ^^ only in a constant loop but I don't know how I would even get started doing that I would REALLY appreciate it if someone could help me with this. The max length of the text has to be 15 characters.
I don't care if it is smooth scrolling.
I want it to be a Winforms application and use .Net framework 4.0.
Here's what I would do, it seemed to work just fine when I tested it out, I created a windows form with a timer and label on it. Make sure to call timer.Start() when you open the form and it will start bouncing around the screen. If you change iUBound to a larger value it will move more spaces across the screen.
string _sPing = "ping";
string _sPong = "pong";
bool bGoingUp = true;
int iUBound = 15;
int iCnt = 1;
public Form1()
{
InitializeComponent();
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
if (bGoingUp)
{
label1.Text = " " + label1.Text;
iCnt++;
}
else
{
label1.Text = label1.Text.Substring(1,label1.Text.Length - 1);
iCnt--;
}
if (iCnt == iUBound)
{
bGoingUp = false;
label1.Text = label1.Text.Replace(_sPing, _sPong);
}
else if (iCnt == 1)
{
bGoingUp = true;
label1.Text = label1.Text.Replace(_sPong, _sPing);
}
}
I'd keep the label contents the same and just move the label, feels like it should be less CPU load and the scrolling will be smoother.
Make a for-loop that runs from 0 to 11 (15 - length of "ping"). With new String(' ', i) you can create a string that is i spaces long. Then set the Text of your label to this space string concatenated with the word "ping".
Now you can make another loop, running from 11 down to 0 doing the same but with the word "pong".
If you enclose both loops in an endless loop (while (true) { ... }) this will run indefinitely.
You also might want to add a pause each time after you set the label text with Thread.Sleep(200). Where you specify the time is in milliseconds.
EDIT (since it is not homework):
Go to the events tab in the properties window and add a Shown event handler
private void frmMarquee_Shown(object sender, EventArgs e)
{
while (true) {
for (int i = 0; i <= 11; i++) {
label1.Text = new String(' ', i) + "ping";
System.Threading.Thread.Sleep(100);
Application.DoEvents();
}
for (int i = 11; i >= 0; i--) {
label1.Text = new String(' ', i) + "pong";
System.Threading.Thread.Sleep(100);
Application.DoEvents();
}
}
}
Note, this solution is not perfect, as the form will not close properly. You will have to abort the program. A solution using a timer will work smoother and the form will behave as expected when closing, however this is a straightforward and simple solution.
I found this example. Pretty close to what you want. The two key elements are (1)using StringBuilder functions to append characters and (2) an asynchronous delegate to put the animation in a different thread.
The idea of the StringBuilder is great because it should be more efficient that dealing with String. And I like Asynchronous delegate because it sounds way more impressive than Timer
Here is my scenario:
On a form I have list of direcotories, Button and control to display multiline text.
In a loop I try to find all files in each directory and delete them.
When file is deleted i want to add text to multiline control.
My problem is that when text is added I can not do anything else. Form is blocked and if I try do do anytching it just stops responding.
Files are deleted using BackgroundWorker
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
//this is datatable with directories and other info
MainDataset.CZYSZCZENIEDataTable CZYSZCZENIE = e.Argument as MainDataset.CZYSZCZENIEDataTable;
CzyscPliki(CZYSZCZENIE, ReportProgress);
}
private void CzyscPliki(MainDataset.CZYSZCZENIEDataTable CZYSZCZENIE, ReportProgressDel del)
{
DirectoryInfo dir = null;
FileInfo[] files = null;
bool subfolder = false;
string katalog = "";
string maska = "";
string[] maski = null;
long total=0;
string dirS;
string fileS;
long fileLen;
//foreach directory to delete
foreach (DataRow r in CZYSZCZENIE.Rows)
{
//CanRead - check if row is not deleted or detached
//r["CZYSC"].AsBool() - check if directory should be cleared
if (r.CanRead() && r["CZYSC"].AsBool())
{
subfolder = r["PODKATALOGI"].AsBool();
katalog = r["KATALOG"].AsString().TrimEnd('\\');
maska = r["MASKA"].AsString();
if (maska.IsEmpty())
maska = "*";
maski = maska.Split(';');
dir = new DirectoryInfo(katalog);
if (dir.Exists)
{
foreach (string s in maski)
{
files = dir.GetFiles(s, (subfolder ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly));
dir.GetFiles();
foreach (FileInfo f in files)
{
dirS = f.Directory.FullName;
fileS = f.Name;
fileLen = f.Length;
try
{
f.Delete();
total += fileLen;
if (del != null)
//here is problem: del - delegate to report state
//when it is called it blocks form
del(dirS, fileS, fileLen, total);
}
catch (Exception ex)
{ }
}
}
}
}
}
}
//this is the delegate that appends text in multiline control
//memoEdit1 is the control
//ceReportProgress.Checked - check if report should be added
private void ReportProgress(string directory, string file, long size, long totalSize)
{
if (memoEdit1.InvokeRequired)
{
memoEdit1.BeginInvoke(new Action<string, string, long, long>(ReportProgress), directory, file, size, totalSize);
}
else
{
if (ceReportProgress.Checked)
{
if (file.IsEmpty())
memoEdit1.AppendText("\r\nCzyszczenie katalogu " + directory);
else
{
memoEdit1.AppendText(file);
if (size > 0)
{
if (size > 1048576)
{
decimal d = size / 1048576;
d = decimal.Round(d, 2);
memoEdit1.AppendText("\tWielkość : " + d.AsString() + " megabajtów", false);
}
else if (size > 1024)
{
decimal d = (decimal)size / (decimal)1024;
d = decimal.Round(d, 2);
memoEdit1.AppendText("\tWielkość : " + d.AsString() + " kilobajtów", false);
}
else
memoEdit1.AppendText("\tWielkość : " + size.AsString() + " bajtów", false);
}
if (totalSize > 0)
{
if (totalSize > 1073741824)
{
decimal d = (decimal)totalSize / (decimal)1073741824;
d = decimal.Round(d, 2);
memoEdit1.AppendText("Zwolniono dotychczas : " + d.AsString() + " gigabajtów");
}
else if (totalSize > 1048576)
{
decimal d = (decimal)totalSize / (decimal)1048576;
d = decimal.Round(d, 2);
memoEdit1.AppendText("Zwolniono dotychczas : " + d.AsString() + " megabajtów");
}
else if (totalSize > 1024)
{
decimal d = (decimal)totalSize / (decimal)1024;
d = decimal.Round(d, 2);
memoEdit1.AppendText("Zwolniono dotychczas : " + d.AsString() + " kilobajtów");
}
else
memoEdit1.AppendText("Zwolniono dotychczas : " + totalSize.AsString() + " bajtów");
}
}
//scroll to the end of control
memoEdit1.ScrollToEnd();
}
}
}
How can I improve this to make it not blocking the form?
You are calling ReportProgress too often. Do it more than about 1000 times per second and the UI thread gets flooded with requests that it cannot keep up with. It won't get around to doing its normal duties, which include painting the controls and responding to the mouse and keyboard. It looks frozen. This gets worse when the UI update code gets more expensive, updating text in a TextBox when there's already a lot of text in it can get quite slow.
The diagnostic is still seeing the UI frozen for a while after the BGW stops running, working on emptying the backlog in the invoke request queue, then suddenly jumping back alive when the queue is finally emptied.
You need to throttle the rate at which you call BeginInvoke(). It never makes more sense to call it any more frequently than once every 50 milliseconds, a human cannot perceive the difference beyond that. Collect the info in a List<> so you can BeginInvoke() a lot less frequently. That's still no complete guarantee if your worker can produce results faster than the UI thread could ever keep up with. In which case slowing down the worker would be a fix. Easy by using Invoke instead of BeginInvoke.
If this worker is running asynchronously, then you can have a form which responds to you.
Besides, problems:
You are running the loop in another function - it makes the operation non-reponsive.
You are not even checking if user wants to cancel (just a point i wanted to make) - Handle DoWorkEventArgs's Cancel property inside the foreach loop.
Move the function CzyscPliki's code in the backgroundWorker1_DoWork (it's anyway too tiny).
EDIT:
If you don't want to move the code into DoWork event handler, then better use Thread for more control. I'm not an expert on it but you will find plenty of code on how to implement so.