Delay in a WinForms app without using "await Task.Delay(x)" - c#

I'm creating a poker app and i want to make some sort of simulation of the throwing of the cards effect and to do that I currently use await Task.Delay(x); However this requires async Task and if i switch this method where i do the task.delay(x) to async i will have to change at least 5-6 more into async as well. I suppose this is fine for someone that understand the exact way the asynchronus works. Currently im getting a lot of logic errors simply because i obviously don't know how async and await operators work.. In other words I'm newbie, and is there any alternative to this exact line await Task.Delay(x); I wont use anything else that is connected to async just this line.
Here's the code :
private async Task Shuffle()
{
Bitmap refreshBackImage = new Bitmap(getBack);
bCall.Enabled = false;
bRaise.Enabled = false;
bFold.Enabled = false;
bCheck.Enabled = false;
MaximizeBox = false;
MinimizeBox = false;
bool check = false;
horizontal = tbChips.Left - _settings.Width * 2 - 15;
vertical = pbTimer.Top - _settings.Height - (_settings.Height) / 7;
RNGCrypto random = new RNGCrypto();
for (i = ImgLocation.Length; i > 0; i--)
{
int j = random.Next(i);
string k = ImgLocation[j];
ImgLocation[j] = ImgLocation[i - 1];
ImgLocation[i - 1] = k;
}
for (i = 0; i < 17; i++)
{
Deck[i] = Image.FromFile(ImgLocation[i]);
string[] charsToRemove = { getCards, ".png", "\\" };
foreach (string c in charsToRemove)
{
ImgLocation[i] = ImgLocation[i].Replace(c, string.Empty);
}
Reserve[i] = int.Parse(ImgLocation[i]) - 1;
Holder[i] = new PictureBox
{
SizeMode = PictureBoxSizeMode.StretchImage,
Height = _settings.Height,
Width = _settings.Width
};
Controls.Add(Holder[i]);
Holder[i].Name = "pb" + i;
await Task.Delay(150);
#region Throwing Cards
SetPlayers(Player, i, ref check, 560, 470, refreshBackImage);
SetPlayers(Bot1, i, ref check, 15, 420, refreshBackImage);
SetPlayers(Bot2, i, ref check, 75, 65, refreshBackImage);
SetPlayers(Bot3, i, ref check, 590, 25, refreshBackImage);
SetPlayers(Bot4, i, ref check, 1115, 65, refreshBackImage);
SetPlayers(Bot5, i, ref check, 1160, 420, refreshBackImage);
if (i >= 12)
{
Holder[12].Tag = Reserve[12];
if (i > 12) Holder[13].Tag = Reserve[13];
if (i > 13) Holder[14].Tag = Reserve[14];
if (i > 14) Holder[15].Tag = Reserve[15];
if (i > 15)
{
Holder[16].Tag = Reserve[16];
}
if (!check)
{
horizontal = 410;
vertical = 265;
}
check = true;
if (Holder[i] != null)
{
Holder[i].Anchor = AnchorStyles.None;
Holder[i].Image = refreshBackImage;
//Holder[i].Image = Deck[i];
Holder[i].Location = new Point(horizontal, vertical);
horizontal += 110;
}
}
#endregion
Bot1 = (Bot)FoldedPlayer(Bot1);
Bot2 = (Bot)FoldedPlayer(Bot2);
Bot3 = (Bot)FoldedPlayer(Bot3);
Bot4 = (Bot)FoldedPlayer(Bot4);
Bot5 = (Bot)FoldedPlayer(Bot5);
if (i == 16)
{
if (!restart)
{
MaximizeBox = true;
MinimizeBox = true;
}
Turns();
}
}
Ending();
}

For things like animations, you might want the System.Windows.Forms.Timer component, which raises a periodic event.
You can configure the interval as well as temporarily disabling it entirely.
Note that after the delay, you'll be back to the top of the handler function... it doesn't automatically keep track of where you are in your sequence the way the await keyword automatically resumes at the next line. So you'll need some counter or such to let you know what step of the animation is coming next.

I'm not sure if you want to do the async, because it wont come back until it's complete. Meaning if you want something timed. Async will have some trouble providing this for you. Because you'll either have to wait for the response which may be an issue. Especially if its a game. Watch how the async functions in debug and you'll understand. An event trigger, or just a timed event will work much better because you'll have the control of when it triggers or how a long you wait for the event. This will get rid of your delay all together or it should.
In your case, a simple trigger event at the time, will display the throwing of cards, and once finished will continue on with your function. That's simple terms, you may have to do a few things like waiting until that trigger is finished. Either way there is a ton of information regarding events. Have a look before you go for async. Since it's forms you can do it however you please, if it for windows phone or other types of systems some require async only.
this should help:
https://msdn.microsoft.com/en-us/library/wkzf914z(v=vs.90).aspx

Related

For loop not executing all code - no errors

https://simmer.io/#JammerLamma/~c09dd45e-0528-01ce-e641-e4a56fb9cfed
https://github.com/JammerLamma/Number-Muncher-Clone
I'm creating a number munchers clone, and the integer variables are not getting properly assigned. It works for a few games, but after a few times of winning, and/or clicking quit, and choosing another game it appears the for loop goes through properly. The game says there are 5 maxCorrect, and correctOnBoard is also set to 5, so I assume the loop goes through 5 times, however, only 4 tiles get set as correct, then sometimes 2, or 4, but never 5 again. It always works as intended the first game.
If I comment out //AssignRest(); the problem still persists.
public void GenerateEven()
{
//GameObject smasher = Instantiate(smasherPF, transform.position, transform.rotation);
remainingNumbers = totalTiles - maxCorrect;
GetLists();
GetTiles();
AssignEven();
RemoveDuplicates(evenNumbers);
AssignRest();
}
private void AssignEven()
{
int maxCorrect = 5;
for (int i = 1; i <= maxCorrect; i++)
{
randomChild = children[UnityEngine.Random.Range(0, children.Count)];
int maxLength = evenNumbers.Count;
int tempTileNum = evenNumbers[UnityEngine.Random.Range(0, maxLength)];
randomChild.GetComponent<Tile>()._TileNumber = tempTileNum;
randomChild.GetComponent<Tile>()._IsCorrect = true;
correctOnBoard++;
randomChild.GetComponent<SpriteRenderer>().sprite = numberSprite[tempTileNum - 1];
Debug.Log(tempTileNum);
}
}
Some things are serialized for debugging purposes. All of the lists get generated correctly.
Changed the code to
private void AssignEven()
{
for (int i = 1; i <= maxCorrect;)
{
randomChild = children[UnityEngine.Random.Range(0, children.Count)];
if(randomChild.GetComponent<Tile>()._IsCorrect == false)
{
int maxLength = evenNumbers.Count;
int tempTileNum = evenNumbers[UnityEngine.Random.Range(0, maxLength)];
randomChild.GetComponent<Tile>()._TileNumber = tempTileNum;
randomChild.GetComponent<Tile>()._IsCorrect = true;
correctOnBoard++;
randomChild.GetComponent<SpriteRenderer>().sprite = numberSprite[tempTileNum - 1];
Debug.Log(tempTileNum);
i++;
}
}
}
Thanks to John Wu!

Why doesn't Debug.Log work in this for loop?

Here is what I have. This DrawPoints() method is called in an Update() method, meaning it is called repeatedly if it doesn't have extra conditions if I understand correctly. So basically I'm trying to make the for loop only run once by putting the outside if (iTrack == 0) check on it.
What is weird is that the Debug.Log commands will not run at all (the text "Here 1" or "Here2" never show up in Console), BUT the other code inside like var lerpedPosition and whatToSpawnClone run.
Why don't the Debug Log commands work? Is there something obviously wrong I'm doing with this code? This is very confusing.
int iTrack = 0;
int matricesNumber = 2;
public void DrawPoints()
{
int startIndex = 0;
int endIndex = mesh.vertexCount;
float t = Mathf.Clamp((Time.time % 2f) / 2f, 0f, 1f);
if (iTrack == 0) {
if (matricesNumber == 2)
{
for (int i = startIndex; i < endIndex; i++)
{
Debug.Log("Here 1");
var lerpedPosition = Vector3.Lerp(matrices1[i].position, matrices2[i].position, t);
whatToSpawnClone = Instantiate(whatToSpawnPrefab, lerpedPosition, matrices2[i].rotation) as GameObject;
if (i == (endIndex - 1))
{
Debug.Log("Here 2");
iTrack = 1;
}
}
}
}
}
Based on the description of your question I will assume that you are creating a script for Unity from here on out. Take a look at this. It offers two solutions that would be worth a try, mainly the second one as it is as simple as a check to make sure you have Debug output enabled for the console.

Prevent scrollbar position from being changed in richtextbox?

I have the following code:
private void HighlightSyntax(string syntax)
{
Regex regex = null;
switch (syntax)
{
case ".xml":
regex = new Regex(#"<\/?[^>\/]*>");
break;
}
if (regex != null)
{
Input.BeginUpdate();
// I want to save scrollbar position here and then restore it
// or maybe even disable it from being changed
int lastIndex = Input.SelectionStart;
int lastLength = Input.SelectionLength;
Input.SelectAll();
// gets matches
var matches = regex.Matches(Input.Text).Cast<Match>().ToArray();
if (matches.Length > 0) // divide into tasks and select all matches
{
Color color = Color.ForestGreen;
int wordsPerTask = 500;
int tasksAmount = (matches.Length / wordsPerTask) + 1;
int start = 0;
int end = matches.Length - 1;
Task[] tasks = new Task[tasksAmount];
for (int i = 0; i < tasksAmount; i++)
{ // dividing
start = matches.Length / tasksAmount * i;
end = matches.Length / tasksAmount * (i + 1) - 1;
var start1 = start;
var end1 = end;
tasks[i] = Task.Run(() => { SelectMatchesInArr(matches, start, end, color); } );
}
if (matches.Length - 1 - end > 0)
SelectMatchesInArr(matches, end + 1, matches.Length - 1, color);
Task.WaitAll(tasks);
}
Input.Select(lastIndex, lastLength);
Input.SelectionColor = Color.Black;
// Restore Input.ScrollBarPosition here
Input.EndUpdate();
}
}
// selects matches from start to end Indexes with Color color.
private void SelectMatchesInArr(Match[] matches, int startIndex, int endIndex, Color color)
{
for (int i = startIndex; i <= endIndex; i++)
{
int selectionStart = Input.SelectionStart;
lock (_locker)
{
Input.Select(matches[i].Index, matches[i].Length);
Input.SelectionColor = color;
Input.DeselectAll();
Input.SelectionStart = selectionStart;
Input.SelectionLength = 0;
}
}
}
It highlights syntax in richtexbox, if regex matches anything related to that syntax. It all worked until I decided to divide selecting into multiple tasks.
After dividing the selection into multiple tasks, my scrollbar position is not stable. Well, I want it to be stable, I don't want it to be changed via code. How do I prevent it from being changed if I have multiple tasks manipulating over richtextbox? What should I do in my situation? Also check comments in the code, they are written in order to help you explain what I want to do.
By the way, the BeginUpdate() and EndUpdate() methods are extension methods that have been taken from here: Hans Passant's derived from richtextbox class
Maybe it would be better to use multithreading only for generating the list of matches and then use them for highlighting?
Also, it seems a bit dangerous to modify UI in multiple threads without any synchronization since it's possible that one thread would call 'Input.Select' and the other one 'Input.DeselectAll' before the first one will set the color.
Applying UI changes in one thread would eliminate that possibility.

Slow Camera Capture

I am using Windows 8's media capture class to click a photo in a desktop application and copy it to clipboard.
My function takes two inputs as argument,
1) the desired device (front, back or usb web cam) and
2) the desired resolution
Here is the function:
async public void UseCamera(int x, int y)
{
MediaCapture _mediaCapture = new MediaCapture();
var _ImageFormat = ImageEncodingProperties.CreatePng();
var _fileStream = new InMemoryRandomAccessStream();
MediaCaptureInitializationSettings _cameraSettings1 = new MediaCaptureInitializationSettings();
DeviceInformationCollection _deviceInformationCollection = null;
IReadOnlyList<IMediaEncodingProperties> res;
_deviceInformationCollection = await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture);
if (x > _deviceInformationCollection.Count - 1)
{
MessageBox.Show("Device Not found");
}
else
{
_cameraSettings1.VideoDeviceId = _deviceInformationCollection[x].Id;
_cameraSettings1.AudioDeviceId = "";
_cameraSettings1.PhotoCaptureSource = PhotoCaptureSource.VideoPreview;
_cameraSettings1.StreamingCaptureMode = StreamingCaptureMode.Video;
await _mediaCapture.InitializeAsync(_cameraSettings1);
res = _mediaCapture.VideoDeviceController.GetAvailableMediaStreamProperties(MediaStreamType.VideoPreview);
uint maxResolution = 0;
List<int> indexMaxResolution = new List<int>();
if (res.Count >= 1)
{
for (int i = 0; i < res.Count; i++)
{
VideoEncodingProperties vp = (VideoEncodingProperties)res[i];
if (vp.Width > maxResolution)
{
indexMaxResolution.Add(i);
maxResolution = vp.Width;
}
}
indexMaxResolution.Reverse();
if (y > indexMaxResolution.Count())
{
MessageBox.Show("Maximum supported resolution index : " + (indexMaxResolution.Count - 1).ToString());
}
//this is the part that I believe is the trouble maker
else
{
await _mediaCapture.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.VideoPreview, res[indexMaxResolution.ElementAt(y)]);
await _mediaCapture.CapturePhotoToStreamAsync(_ImageFormat, _fileStream);
Clipboard.SetImage(Image.FromStream(_fileStream.AsStream()));
}
}
}
}
The function is working, but the problem is that it is incredibly slow.. it takes almost 4-5 seconds to capture a photo. Can anyone tell me where am i going wrong and how can I speed things up. Because I tested my camera, and it can take clicks # almost 2 pics per second..
If you move all the initialization and device information queries to an initialization function you might see an increase in speed.
In my experience gathering device information is slow.
Try to do as much as possible upfront so that when the time comes to capture, only the necessary things need to be done.

threading timer not working, why?

i have a program which i have a threading timer to update the time coming from the data server. However, i notice the timer run a few times and stop calling afterwards. i try and copy the threading timer code onto a new program and it runs fine, so i know somehow the timer code must have interfere with the rest of the program, but i dont know where, can anyone help me out please?
the program is quite big to post everything here, i try to post all the relevant parts here.
public partial class HistoricalDownload : Form
{
static int column = 2;
static int row = 100;
string timeFmt = "yyyy/MM/dd HH:mm:ss.fff";
ZenFire.Connection zf;
ZenFire.Connection.TickEventHandler tick;
ZenFire.IProduct product = null;
System.Windows.Forms.TextBox[,] textbox = new System.Windows.Forms.TextBox[column, row];
DisplayTimer displayTimer = new DisplayTimer();
memoryStreamClass msc = new memoryStreamClass();
Dictionary<string, int> dictionarySymbol = new Dictionary<String, int>();
delegate void StringParameterDelegate(int j, string value);
public HistoricalDownload(ZenFire.Connection z)
{
InitializeComponent();
int month = 0;
int year = 0;
string symbol;
string exchange;
string finalSymbol;
string[] lineSplit;
zf = z;
tick = new ZenFire.Connection.TickEventHandler(zf_TickEvent);
zf.TickEvent += tick;
//set the array for name and update time
for (int k = 0; k < column; k++)
{
for (int j = 0; j < row; j++)
{
textbox[k, j] = new System.Windows.Forms.TextBox();
textbox[k, j].Size = new Size(140, 18);
textbox[k, j].Name = "textbox_" + k + "_" + j;
if (j >= 50)
{
textbox[k, j].Location = new System.Drawing.Point((k * 140) + 400, ((j - 50) * 18) + 30);
}
else
{
textbox[k, j].Location = new System.Drawing.Point((k * 140) + 20, (j * 18) + 30);
}
textbox[k, j].Visible = true;
Controls.Add(textbox[k, j]);
}
}
//load the config file and subscribe the symbol
....
///////////////////////////////////////
System.Threading.TimerCallback displayCallback = new System.Threading.TimerCallback(timeDisplay);
System.Threading.Timer displayTimerThread = new System.Threading.Timer(displayCallback, displayTimer, 0, 1000);
}
public void timeDisplay(object timerObject)
{
DisplayTimer t = (DisplayTimer)timerObject;
for (int j = 0; j < t.row; j++)
{
string value = t.outputTime[j].ToString(timeFmt);
if (value != "0001/01/01 00:00:00.000")
{
writeToTextBox(j, value);
}
}
}
public void writeToTextBox(int j, string value)
{
if (InvokeRequired)
{
BeginInvoke(new StringParameterDelegate(writeToTextBox), new object[] { j, value });
return;
}
//// Must be on the UI thread if we've got this far
textbox[1, j].Text = value;
}
void zf_TickEvent(object sender, ZenFire.TickEventArgs e)
{
string product = e.Product.ToString();
int c = dictionarySymbol[product];
displayTimer.outputTime[c] = e.TimeStamp;
msc.fillBuffer(string.Format("{0},{1},{2},{3},{4}\r\n",
e.TimeStamp.ToString(timeFmt),
product,
Enum.GetName(typeof(ZenFire.TickType), e.Type),
e.Price,
e.Volume));
}
can anyone points out where the interference might be?
If all your're doing in your timer callback is updating the UI, I'd suggest using System.Windows.Forms.Timer instead. You don't have to deal with InvokeRequired/BeginInvoke because that handler runs on the UI thread.
It also appears that you using a local variable for your System.Thread.Timer. That could cause the timer to be finalized after the execution of HistoricalDownload. Which is probably much sooner than you want the timer to stop running. (see first Note at http://msdn.microsoft.com/en-us/library/saba8ksx) You should put that variable in a field of the parent class--or whatever class will stay "alive" as long as you want the timer to run. I don't think that would be an issue if you used System.Windows.Forms.Timer. But, it's a good idea too keep a field around for something that get's used asynchronously.
The Tick event for the timer may be occurring on a ThreadPool thread (many of the framework timers do this, but since you're using a custom timer (ZenFire?), it's impossible to know for sure).
If this is the case, your code is likely not thread safe, and you may be getting an exception within your timer's Tick event. Again, depending on the implementation, the exception may be preventing the timer from functioning correctly after that point.
The particular things to watch for are to not update any UI components from the timer's Tick event - but install, marshal the calls back to the UI thread with Control.Invoke (or Dispatcher.Invoke if you're using WPF). Also, simple things like using your Dictionary<T,U> are not thread safe, so you should synchronize access to these items.

Categories

Resources