Why the unpredictable results when using async await on key events - winforms

I do not understand why I am getting strange results on key events in a winForm app using async await on keydown in a form. Here is very simple demo of my issue.
The complete app:
using System.Drawing;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
int counter = 0;
private async void Form1_KeyDown(object sender, KeyEventArgs e)
{
await HandleKeypress();
}
private async Task HandleKeypress()
{
switch (counter)
{
case 0:
label1.BackColor = Color.Red;
label2.BackColor = Color.White;
label3.BackColor = Color.White;
break;
case 1:
label1.BackColor = Color.White;
label2.BackColor = Color.Red;
label3.BackColor = Color.White;
break;
case 2:
label1.BackColor = Color.White;
label2.BackColor = Color.White;
label3.BackColor = Color.Red;
label3.Refresh();
await Task.Delay(5000);
break;
}
counter++;
if (counter == 3)
{
counter = 0;
}
}
}
}
The form KeyPreview is on and a KeyDown event on the form
fires the async method. A counter is incremented from 0 to 3 when it reaches 3 the counter is reset to 0.There are three labels depending on the counter value 0,1,2 the corresponding labels background is set to red and the the other two back to white. There is 5 second delay on when the counter == 2. If I keep pressing the enter key when the counter == 2 I would expect label 3 to go to red and the other two labels to reset to white. Then after 5 seconds I would expect label1 to revert to red and the sequence to continue. This is not what happens and the sequence becomes somewhat caotic. Why does this happen.You have to keep pressing a key.

If you can cancel the keypress with a bool (cancelAction) set before the delay then the desired action can be accomplished.
int counter = 0;
bool cancelAction = false;
private async void Form1_KeyDown(object sender, KeyEventArgs e)
{
await HandleKeypress();
}
private async Task HandleKeypress()
{
if (cancelAction)
{
return;
}
switch (counter)
{
case 0:
label1.BackColor = Color.Red;
label2.BackColor = Color.White;
label3.BackColor = Color.White;
break;
case 1:
label1.BackColor = Color.White;
label2.BackColor = Color.Red;
label3.BackColor = Color.White;
break;
case 2:
label1.BackColor = Color.White;
label2.BackColor = Color.White;
label3.BackColor = Color.Red;
label3.Refresh();
cancelAction = true;
await Task.Delay(5000);
cancelAction = false;
break;
}
counter++;
if (counter == 3)
{
counter = 0;
}
}

Related

How to use keyboard in wpf calculator

Enter button is not working when i try to get the result
public partial class Window1 : Window
{
static MyTextBox DisplayBox;
static MyTextBox PaperBox;
static PaperTrail Paper;
public Window1()
: base()
{
InitializeComponent();
//sub-class our textBox
//DisplayBox = new MyTextBox();
//Grid.SetRow(DisplayBox, 0);
//Grid.SetColumn(DisplayBox, 0);
//Grid.SetColumnSpan(DisplayBox, 9);
//DisplayBox.Height = 30;
//MyGrid.Children.Add(DisplayBox);
//sub-class our paper trail textBox
PaperBox = new MyTextBox();
Grid.SetRow(PaperBox, 1);
Grid.SetColumn(PaperBox, 0);
Grid.SetColumnSpan(PaperBox, 3);
Grid.SetRowSpan(PaperBox, 5);
PaperBox.IsReadOnly = true;
PaperBox.VerticalScrollBarVisibility = ScrollBarVisibility.Visible;
PaperBox.Margin = new Thickness(3.0,1.0,1.0,1.0);
PaperBox.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
Paper = new PaperTrail();
MyGrid.Children.Add(PaperBox);
ProcessKey('0');
EraseDisplay = true;
}
private enum Operation
{
None,
Devide,
Multiply,
Subtract,
Add,
Percent,
Sqrt,
OneX,
Negate
}
private Operation LastOper;
private string _display;
private string _last_val;
private string _mem_val;
private bool _erasediplay;
//flag to erase or just add to current display flag
private bool EraseDisplay
{
get
{
return _erasediplay;
}
set
{
_erasediplay = value;
}
}
//Get/Set Memory cell value
private Double Memory
{
get
{
if (_mem_val == string.Empty)
return 0.0;
else
return Convert.ToDouble(_mem_val);
}
set
{
_mem_val = value.ToString();
}
}
//Lats value entered
private string LastValue
{
get
{
if (_last_val == string.Empty)
return "0";
return _last_val;
}
set
{
_last_val = value;
}
}
//The current Calculator display
private string Display
{
get
{
return _display;
}
set
{
_display = value;
}
}
// Sample event handler:
private void OnWindowKeyDown(object sender, System.Windows.Input.TextCompositionEventArgs /*System.Windows.Input.KeyEventArgs*/ e)
{
string s = e.Text;
char c = (s.ToCharArray())[0];
e.Handled = true;
if ((c >= '0' && c <= '9') || c == '.' || c == '\b') // '\b' is backspace
{
ProcessKey(c);
return;
}
switch (c)
{
case '+':
ProcessOperation("BPlus");
break;
case '-':
ProcessOperation("BMinus");
break;
case '*':
ProcessOperation("BMultiply");
break;
case '/':
ProcessOperation("BDevide");
break;
case '%':
ProcessOperation("BPercent");
break;
case '=':
ProcessOperation("BEqual");
break;
}
}
private void DigitBtn_Click(object sender, RoutedEventArgs e)
{
string s = ((Button)sender).Content.ToString();
//char[] ids = ((Button)sender).ID.ToCharArray();
char[] ids = s.ToCharArray();
ProcessKey(ids[0]);
}
private void ProcessKey(char c)
{
if (EraseDisplay)
{
Display = string.Empty;
EraseDisplay = false;
}
AddToDisplay(c);
}
private void ProcessOperation(string s)
{
Double d = 0.0;
switch (s)
{
case "BPM":
LastOper = Operation.Negate;
LastValue = Display;
CalcResults();
LastValue = Display;
EraseDisplay = true;
LastOper = Operation.None;
break;
case "BDevide":
if (EraseDisplay) //stil wait for a digit...
{ //stil wait for a digit...
LastOper = Operation.Devide;
break;
}
CalcResults();
LastOper = Operation.Devide;
LastValue = Display;
EraseDisplay = true;
break;
case "BMultiply":
if (EraseDisplay) //stil wait for a digit...
{ //stil wait for a digit...
LastOper = Operation.Multiply;
break;
}
CalcResults();
LastOper = Operation.Multiply;
LastValue = Display;
EraseDisplay = true;
break;
case "BMinus":
if (EraseDisplay) //stil wait for a digit...
{ //stil wait for a digit...
LastOper = Operation.Subtract;
break;
}
CalcResults();
LastOper = Operation.Subtract;
LastValue = Display;
EraseDisplay = true;
break;
case "BPlus":
if (EraseDisplay)
{ //stil wait for a digit...
LastOper = Operation.Add;
break;
}
CalcResults();
LastOper = Operation.Add;
LastValue = Display;
EraseDisplay = true;
break;
case "BEqual":
if (EraseDisplay) //stil wait for a digit...
break;
CalcResults();
EraseDisplay = true;
LastOper = Operation.None;
LastValue = Display;
//val = Display;
break;
case "BSqrt":
LastOper = Operation.Sqrt;
LastValue = Display;
CalcResults();
LastValue = Display;
EraseDisplay = true;
LastOper = Operation.None;
break;
case "BPercent":
if (EraseDisplay) //stil wait for a digit...
{ //stil wait for a digit...
LastOper = Operation.Percent;
break;
}
CalcResults();
LastOper = Operation.Percent;
LastValue = Display;
EraseDisplay = true;
//LastOper = Operation.None;
break;
case "BOneOver":
LastOper = Operation.OneX;
LastValue = Display;
CalcResults();
LastValue = Display;
EraseDisplay = true;
LastOper = Operation.None;
break;
case "BC": //clear All
LastOper = Operation.None;
Display = LastValue = string.Empty;
Paper.Clear();
UpdateDisplay();
break;
case "BCE": //clear entry
LastOper = Operation.None;
Display = LastValue;
UpdateDisplay();
break;
case "BMemClear":
Memory = 0.0F;
DisplayMemory();
break;
case "BMemSave":
Memory = Convert.ToDouble(Display);
DisplayMemory();
EraseDisplay = true;
break;
case "BMemRecall":
Display = /*val =*/ Memory.ToString();
UpdateDisplay();
//if (LastOper != Operation.None) //using MR is like entring a digit
EraseDisplay = false;
break;
case "BMemPlus":
d = Memory + Convert.ToDouble(Display);
Memory = d;
DisplayMemory();
EraseDisplay = true;
break;
}
}
private void OperBtn_Click(object sender, RoutedEventArgs e)
{
ProcessOperation(((Button)sender).Name.ToString());
}
private double Calc(Operation LastOper)
{
double d = 0.0;
try {
switch (LastOper)
{
case Operation.Devide:
Paper.AddArguments(LastValue + " / " + Display);
d = (Convert.ToDouble(LastValue) / Convert.ToDouble(Display));
CheckResult(d);
Paper.AddResult(d.ToString());
break;
case Operation.Add:
Paper.AddArguments(LastValue + " + " + Display);
d = Convert.ToDouble(LastValue) + Convert.ToDouble(Display);
CheckResult(d);
Paper.AddResult(d.ToString());
break;
case Operation.Multiply:
Paper.AddArguments(LastValue + " * " + Display);
d = Convert.ToDouble(LastValue) * Convert.ToDouble(Display);
CheckResult(d);
Paper.AddResult(d.ToString());
break;
case Operation.Percent:
//Note: this is different (but make more sense) then Windows calculator
Paper.AddArguments(LastValue + " % " + Display);
d = (Convert.ToDouble(LastValue) * Convert.ToDouble(Display)) / 100.0F;
CheckResult(d);
Paper.AddResult(d.ToString());
break;
case Operation.Subtract:
Paper.AddArguments(LastValue + " - " + Display);
d = Convert.ToDouble(LastValue) - Convert.ToDouble(Display);
CheckResult(d);
Paper.AddResult(d.ToString());
break;
case Operation.Sqrt:
Paper.AddArguments("Sqrt( " + LastValue + " )");
d = Math.Sqrt(Convert.ToDouble(LastValue));
CheckResult(d);
Paper.AddResult(d.ToString());
break;
case Operation.OneX:
Paper.AddArguments("1 / " + LastValue);
d = 1.0F / Convert.ToDouble(LastValue);
CheckResult(d);
Paper.AddResult(d.ToString());
break;
case Operation.Negate:
d = Convert.ToDouble(LastValue) * (-1.0F);
break;
}
}
catch {
d = 0;
Window parent = (Window)MyPanel.Parent;
Paper.AddResult("Error");
MessageBox.Show(parent, "Operation cannot be perfomed", parent.Title);
}
return d;
}
private void CheckResult(double d)
{
if (Double.IsNegativeInfinity(d) || Double.IsPositiveInfinity(d) || Double.IsNaN(d))
throw new Exception("Illegal value");
}
private void DisplayMemory()
{
if (_mem_val != String.Empty)
BMemBox.Text = "Memory: " + _mem_val;
else
BMemBox.Text = "Memory: [empty]";
}
private void CalcResults()
{
double d;
if (LastOper == Operation.None)
return;
d = Calc(LastOper);
Display = d.ToString();
UpdateDisplay();
}
private void UpdateDisplay()
{
if (Display == String.Empty)
DisplayBox.Text = "0";
else
DisplayBox.Text = Display;
}
private void AddToDisplay(char c)
{
if (c == '.')
{
if (Display.IndexOf('.', 0) >= 0) //already exists
return;
Display = Display + c;
}
else
{
if (c >= '0' && c <= '9') {
Display = Display + c;
}
else
if (c == '\b') //backspace ?
{
if (Display.Length <= 1)
Display = String.Empty;
else
{
int i = Display.Length;
Display = Display.Remove(i - 1, 1); //remove last char
}
}
}
UpdateDisplay();
}
void OnMenuAbout(object sender, RoutedEventArgs e)
{
Window parent = (Window)MyPanel.Parent;
MessageBox.Show(parent, parent.Title + " - By Jossef Goldberg ", parent.Title,MessageBoxButton.OK, MessageBoxImage.Information);
}
void OnMenuExit(object sender, RoutedEventArgs e)
{
this.Close();
}
void OnMenuStandard(object sender, RoutedEventArgs e)
{
//((MenuItem)ScientificMenu).IsChecked = false;
((MenuItem)StandardMenu).IsChecked = true; //for now always Standard
}
//Not implemenetd
void OnMenuScientific(object sender, RoutedEventArgs e)
{
//((MenuItem)StandardMenu).IsChecked = false;
}
private class PaperTrail
{
string args;
public PaperTrail()
{
}
public void AddArguments(string a)
{
args = a;
}
public void AddResult(string r)
{
PaperBox.Text += args + " = " + r + "\n";
}
public void Clear()
{
PaperBox.Text = string.Empty;
args = string.Empty;
}
}
}
<
my keyboard is not working specially equal to operator so my intention is when i click on enter button from keyboard the calculator should show result>.
private void _KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter || e.Key == Key.Tab)
{
//YourCode
}
}
private void txtEdtDisplayBox_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
string rest = txtEdtDisplayBox.Text;
string[] seperaateNumbers;
seperaateNumbers = rest.Split('+');
if (seperaateNumbers.Count() > 1)
{
txtEdtDisplayBox.Text = Convert.ToString(Convert.ToInt64(seperaateNumbers[0]) + Convert.ToInt64(seperaateNumbers[1]));
//MessageBox.Show( Convert.ToString(Convert.ToInt64(seperaateNumbers[0]) + Convert.ToInt64(seperaateNumbers[1])));
}
else
{
DXMessageBox.Show("Wrong Operation","Error", MessageBoxButton.OK,MessageBoxImage.Error);
}
seperaateNumbers = rest.Split('-');
if (seperaateNumbers.Count() > 1)
{
txtEdtDisplayBox.Text = Convert.ToString(Convert.ToInt64(seperaateNumbers[0]) + Convert.ToInt64(seperaateNumbers[1]));
}
seperaateNumbers = rest.Split('*');
if (seperaateNumbers.Count() > 1)
{
txtEdtDisplayBox.Text = Convert.ToString(Convert.ToInt64(seperaateNumbers[0]) + Convert.ToInt64(seperaateNumbers[1]));
}
seperaateNumbers = rest.Split('/');
if (seperaateNumbers.Count() > 1)
{
txtEdtDisplayBox.Text = Convert.ToString(Convert.ToInt64(seperaateNumbers[0]) + Convert.ToInt64(seperaateNumbers[1]));
}
}
}

UISwipeGestureRecogniser not being recognised

I have a UIScrollView into which I am creating and adding UILabels containing the results of a simple LINQ query.
I have set up a UISwipeGestureRecognizer within the loop that generates the labels (iOS: issues with UIGestureRecognisers vs Subviews says I need a new recogniser for each control - I'm assuming I can do with a UILabel the same as UIImageView for adding a recogniser) and then added the recogniser to the label.
When the view containing the UIScrollView is started, the scrollview works as expected, but the swipe isn't.
Caveat : only tried this on the simulator, my iPhone is acting up.
private void CreateViewHistory()
{
float xtext = 4f;
float y = 4f;
int c = 0;
var tv = tank.Events.OrderByDescending(t => t.Date).ToList();
tbiHistClearAll.Enabled = enableDelete;
//tgrRemove.AddTarget(this, new Selector("screenSwipe"));
//pgrRemove.DelaysTouchesBegan = true;
foreach (var e in tv)
{
var tgrRemove = new UISwipeGestureRecognizer()
{
NumberOfTouchesRequired = 1,
Direction = UISwipeGestureRecognizerDirection.Right,
};
tgrRemove.AddTarget(this, new Selector("screenSwipe"));
svHistoryEvents.PanGestureRecognizer.RequireGestureRecognizerToFail(tgrRemove);
string info = string.Format("{0} - {1}{2} ({3})\n{4} - {5}\n{6} - {7}\n{8} - {9}", e.EventType, e.Volume, AppDelegate.Self.db.getShortVolumeUnits(), e.Date.ToShortDateString(),
StringUtils.GetString("Sowcrop.Implement"), e.Implement != null ? e.Implement.ImplementType : StringUtils.GetString("Common.NonRecorded"),
StringUtils.GetString("Common.User"), StringUtils.GetString("Common.NonRecorded"),
StringUtils.GetString("Common.Notes"), !string.IsNullOrEmpty(e.Notes) ? e.Notes : StringUtils.GetString("Common.NonRecorded"));
var lbl = new UILabel()
{
UserInteractionEnabled = true
};
lbl = UICreation.MakeLabelWithTag(svHistoryEvents, new RectangleF(xtext, y, 320f, 90f), info, UITextAlignment.Left, UIColor.Black, false, 4, c);
lbl.AddGestureRecognizer(tgrRemove);
svHistoryEvents.AddSubview(lbl);
lblTemp.Add(lbl);
c++;
y += 94f;
}
UIUtils.ResizeScrollView(svHistoryEvents);
}
[Export("screenSwipe")]
public void SwipeRemove(UIGestureRecognizer s)
{
var swipe = s as UIGestureRecognizer;
var tv = tank.Events.OrderByDescending(t => t.Date).ToList();
var txt = swipe.View as UILabel;
switch (swipe.State)
{
case UIGestureRecognizerState.Began:
Console.WriteLine("Swipe began");
break;
case UIGestureRecognizerState.Changed:
Console.WriteLine("Swipe changed");
tv.RemoveAt(txt.Tag);
CreateViewHistory();
break;
case UIGestureRecognizerState.Ended:
Console.WriteLine("Swipe ended");
break;
case UIGestureRecognizerState.Cancelled:
Console.WriteLine("Swipe cancelled");
break;
}
}
MakeLabelWithTag generates a UILabel which can then be added to the scrollview.
Am I missing something here, or do I need to do something special as the label is held within a scrollview?
I've also tried what has been suggested at UISwipeGestureRecogniser in a UIScrollView, but still without success.
Found the problem and it's probably the dumbest thing I've encountered in a long time!
To get the swipe gesture to work within a scrollview, you have to first encompass whatever it is you want to add within a UIView and then add that to the scrollview.
To therefore get a swipe within a scrollview to work, you need to do the following
private void CreateViewHistory()
{
foreach (var i in svHistoryEvents.Subviews)
if (i is UIView)
i.RemoveFromSuperview();
float xtext = 4f;
float y = 4f;
int c = 0;
tbiHistClearAll.Enabled = enableDelete;
foreach (var e in tv)
{
var tgrRemove = new UISwipeGestureRecognizer()
{
NumberOfTouchesRequired = 1,
Direction = UISwipeGestureRecognizerDirection.Right,
};
tgrRemove.AddTarget(this, new Selector("screenSwipe"));
var view = new UIView(new RectangleF(xtext, y, 320f, 90f));
svHistoryEvents.PanGestureRecognizer.RequireGestureRecognizerToFail(tgrRemove);
string info = string.Format("{0} - {1}{2} ({3})\n{4} - {5}\n{6} - {7}\n{8} - {9}", e.EventType, e.Volume, AppDelegate.Self.db.getShortVolumeUnits(), e.Date.ToShortDateString(),
StringUtils.GetString("Sowcrop.Implement"), e.Implement != null ? e.Implement.ImplementType : StringUtils.GetString("Common.NonRecorded"),
StringUtils.GetString("Common.User"), StringUtils.GetString("Common.NonRecorded"),
StringUtils.GetString("Common.Notes"), !string.IsNullOrEmpty(e.Notes) ? e.Notes : StringUtils.GetString("Common.NonRecorded"));
var lbl = new UILabel()
{
UserInteractionEnabled = true
};
lbl = UICreation.MakeLabelWithTag(svHistoryEvents, new RectangleF(0, 0, 320f, 90f), info, UITextAlignment.Left, UIColor.Black, false, 4, c);
view.AddGestureRecognizer(tgrRemove);
view.AddSubview(lbl);
svHistoryEvents.AddSubview(view);
lblTemp.Add(lbl);
c++;
y += 94f;
}
UIUtils.ResizeScrollView(svHistoryEvents);
}
[Export("screenSwipe")]
public void SwipeRemove(UIGestureRecognizer s)
{
var swipe = s as UIGestureRecognizer;
var txt = swipe.View.Subviews[0] as UILabel;
switch (swipe.State)
{
case UIGestureRecognizerState.Began:
Console.WriteLine("Swipe began");
break;
case UIGestureRecognizerState.Changed:
Console.WriteLine("Swipe changed");
break;
case UIGestureRecognizerState.Ended:
Console.WriteLine("Swipe ended");
tv.RemoveAt(txt.Tag);
CreateViewHistory();
break;
case UIGestureRecognizerState.Cancelled:
Console.WriteLine("Swipe cancelled");
break;
}
}
It is not possible to add just a UILabel and have the swipe act on that, it has to be on a UIView with the label as a subview to it.

Can't get keyListener to work while Timer is running

Hello people of stack overflow, my program has a driver class Frogger(), a JPanel class that calculates everything, pulls together all the necessary panels, and implements keyListener called FroggerPanel(), and another JPanel class that draws everything based on the elements in FroggerPanel() called FroggerDisplayPanel().
Here's a pastebin with the full code: http://pastebin.com/Axrbjej6.
The keyListener works exactly as it should when the Timer isn't started, but as soon as it starts it wont respond at all!
This is where the keyListener is added and focused on in the Frogger() class:
public static void main(String[]args) throws IOException
{
frame = new JFrame("CS125 Frogger");
Frogger startPanel = new Frogger();
FroggerPanel panel = new FroggerPanel();
frame.addKeyListener(panel);
frame.setFocusable(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
}
This is the stepGame() method in FroggerPanel() that is called when the timer delay expires, its mostly concerned with moving all the cars; the Frog Rectangle in the setLocations() method is what I need to respond to the keyListener:
private int current_x_step = 0;
private int lane_bounds = 0;
private int new_pos = 0;
private void stepGame() {
for (int i = 0; i < laneAmt; i++) {
if(i == 0 || i % 2 == 0){
current_x_step = X_STEP_SIZE;
lane_bounds = display.getWidth()+rUnit;
new_pos = -rUnit;
}else if((i-1) == 0 || (i-1) % 2 == 0){
current_x_step = -X_STEP_SIZE;
lane_bounds = -rUnit;
new_pos = DISPLAY_DIM + rUnit;
}
for(int j = 0; j < cars.get(i).size(); j++){
cars.get(i).get(j).x += current_x_step;
if (cars.get(i).get(j).x == lane_bounds) {
cars.get(i).get(j).x = new_pos;
}
if(cars.get(i).get(j).intersects(Frog)){
timer.stop();
startPause.setText("Retry?");
break;
}
}
}
display.setLocations(cars, Frog);
if(Frog.y == 0){
stepLevel();
}
}
This is the keyListener code thats in the FroggerPanel() class:
public void keyPressed(KeyEvent e) {
switch(e.getKeyCode()){
case KeyEvent.VK_W: Frog.y -= rUnit; break;
case KeyEvent.VK_S: Frog.y += rUnit; break;
case KeyEvent.VK_A: Frog.x -= rUnit; break;
case KeyEvent.VK_D: Frog.x += rUnit; break;
}
display.setLocations(cars, Frog);
}
#Override
public void keyReleased(KeyEvent e) {
}
#Override
public void keyTyped(KeyEvent e) {
switch(e.getKeyCode()){
case KeyEvent.VK_W: Frog.y -= rUnit; break;
case KeyEvent.VK_S: Frog.y += rUnit; break;
case KeyEvent.VK_A: Frog.x -= rUnit; break;
case KeyEvent.VK_D: Frog.x += rUnit; break;
}
display.setLocations(cars, Frog);
}
Any suggestions are appreciated, thanks for the help!

Activation before proper Deactivation WP7

In my app I allow the user to go to the marketplace for various reasons. While loading the marketplace, if the user hits the back button very quickly it will try to go back to my apps saved stated. All my data from iso-storage etc is loaded just fine, but the screen is frozen. I have different application bars for various pivot items and as I do the swiping motion, I see the application bar changing, so I know the app is responsive.
The main problem is that the screen is stuck where the user initially launched the marketplace task. I understand that int this edge case, my App and Page constructors are not firing, and the events that are firing are on navigated from, application deactivated, application activated, and on navigated to.
I thought I could use a Boolean to basically cover the case for when a marketplace task has fired so that way I can reload the data context in the on navigated to method and set it to my view model. The screen however is still frozen.
Any help on this issue is greatly appreciated,
Thanks
Edit: Here is some relevant code
private void Application_Activated(object sender, ActivatedEventArgs e)
{
if (!App.ViewModel.IsDataLoaded)
{
App.ViewModel.LoadData();
}
DetermineIsTrial();
}
private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
if (playerController.chapterPlayer != null)
{
var store = new PersistentDataStorage();
store.Backup(StringResource.ChapterPosition, playerController.chapterPlayer.Position);
store.Backup(StringResource.ChapterUriString, playerController.chapterPlayer.Source.OriginalString);
store.Backup(StringResource.NaturalDuration, playerController.chapterPlayer.NaturalDuration.TimeSpan);
}
}
Main Page XAML:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
App.viewIdentifier = StringResource.MainPageView;
if (App.firstTimeLoading == false && PivotBackground.SelectedItem != SuggestedPivotItem)
{
BuildApplicationBar();
}
else if (PivotBackground.SelectedItem == SuggestedPivotItem)
{
BuildMarketPlaceApplicationBar();
}
if (App.firstTimeLoading == true)
{
BuildApplicationBar(); //builds the application bar
//Restore the state from tombstone and set the audioplayer.
App.playerController = new PlayerButtonsController();
App.playerController.SetMediaPlayer(App.MainAudioPlayer);
RestoreState();
ResourceDictionary appResourceList = App.Current.Resources;
App.firstTimeLoading = false;
//default source for chapter position
App.AudioMgr.SetChapterSource(0);
}
}
More methods:
private void RestoreState()
{
var store = new PersistentDataStorage();
playerWasWhere = store.Restore<TimeSpan>(StringResource.ChapterPosition);
naturalDuration = store.Restore<TimeSpan>(StringResource.NaturalDuration);
currentAudioFile = store.Restore<String>(StringResource.ChapterUriString);
SetAudioListScrollPosition();
App.playerController.SetPositionFromIsoStorage(currentAudioFile, playerWasWhere, naturalDuration);
}
public void LoadData()
{
CreateAudioPlayerGUIfromChapterList();
CreateAboutMenuGUIfromExtrasData();
CreateQuotesMenuGUIfromExtrasData();
this.IsDataLoaded = true;
}
private void CreateAudioPlayerGUIfromChapterList()
{
int numberOfChapters = 0;
for (int i = 0; i < App.AudioMgr.Parts.Count; i++)
{
ObservableCollection<ItemViewModel> tempObservableCollection = new ObservableCollection<ItemViewModel>();
for (int j = 0; j < App.AudioMgr.Parts[i].NumberOfChapters; j++)
{
tempObservableCollection.Add(new ItemViewModel()
{
LineOne = ProcessTitle(App.AudioMgr.Chapters[numberOfChapters + j].Title),
LineTwo = App.AudioMgr.Chapters[numberOfChapters + j].StatusMessage,
ItemAlpha = 0.0,
ChapterForeground = ChapterInfo.StatusColor[(int)App.AudioMgr.Chapters[numberOfChapters + j].Status],
Progress = 0,
Width = 0,
UserColorTheme = App.accentBrush,
PlayIconVisible = Visibility.Collapsed,
ChapterDurationProgressBarAdjacent = StringResource.Space,
ContainingPart = i,
MediaStateImageSource = StringResource.KJIcons + App.themeDir + StringResource.AppBarSpeaker
});
}
numberOfChapters += App.AudioMgr.Parts[i].NumberOfChapters;
//no parts header doesn't need spacing or border since its the first header.
if (i == 0 && App.AudioMgr.Parts[i].Title == "")
{
Parts.Add(new PartsViewModel()
{
PartsHeader = StringResource.Space,
ChapterForeground = App.defaultForeground,
ChaptersInPart = tempObservableCollection,
PartsBackgroundBrush = App.partsBackgroundBrush,
PartsHeaderHeight = 0,
PartsBorderThickness = new Thickness(0)
});
}
//parts header needs spacing and border
else if (App.AudioMgr.Parts[i].Title != "")
{
Parts.Add(new PartsViewModel()
{
PartsHeader = App.AudioMgr.Parts[i].Title,
ChapterForeground = App.defaultForeground,
ChaptersInPart = tempObservableCollection,
PartsBackgroundBrush = App.partsBackgroundBrush,
PartsHeaderHeight = double.NaN,
PartsBorderThickness = new Thickness(0,0,0,2)
});
}
else
{
Parts.Add(new PartsViewModel()
{
PartsHeader = StringResource.Space,
ChapterForeground = App.defaultForeground,
ChaptersInPart = tempObservableCollection,
PartsBackgroundBrush = App.partsBackgroundBrush,
PartsHeaderHeight = 0,
PartsBorderThickness = new Thickness(0)
});
}
}
}
private void CreateAboutMenuGUIfromExtrasData()
{
int list_count = 0;
for (int i = 0; i < 3; ++i)
{
switch (i)
{
//Evaluate number of Authors
case 0:
list_count = DictionaryIterator(App.Parser.AboutAuthorsArrayList);
if (list_count == 1)
{
this.About.Add(new ItemViewModel() { LineOne = StringResource.AboutAuthor }); //for one author
}
else if (list_count > 1)
{
this.About.Add(new ItemViewModel() { LineOne = StringResource.AboutAuthors }); //for more than one author
}
break;
//Evaluate number of books (should only be one)
case 1:
list_count = DictionaryIterator(App.Parser.AboutBookArrayList);
if (list_count > 0)
this.About.Add(new ItemViewModel() { LineOne = StringResource.AboutBook });
break;
//Evaluate number of Readers
case 2:
list_count = DictionaryIterator(App.Parser.AboutNarratorsArrayList);
if (list_count == 1)
{
this.About.Add(new ItemViewModel() { LineOne = StringResource.AboutReader }); //for one reader
}
else if (list_count > 1)
{
this.About.Add(new ItemViewModel() { LineOne = StringResource.AboutReaders}); //for more than one reader
}
break;
}
}
}
private void CreateQuotesMenuGUIfromExtrasData()
{
int list_count = 0;
for( int i = 0; i < 6; ++i )
{
switch( i )
{
case 0:
list_count = DictionaryIterator(App.Parser.QuotesAuthorAboutArrayList);
if (list_count == 1)
this.Quotes.Add(new ItemViewModel() { LineOne = StringResource.QuotesAboutAuthor});
else if(list_count > 1)
this.Quotes.Add(new ItemViewModel() { LineOne = StringResource.QuotesAboutAuthors });
break;
case 1:
list_count = DictionaryIterator(App.Parser.QuotesAuthorFromArrayList);
if (list_count == 1)
this.Quotes.Add(new ItemViewModel() { LineOne = StringResource.QuotesFromAuthor });
else if (list_count > 1)
this.Quotes.Add(new ItemViewModel() { LineOne = StringResource.QuotesFromAuthors});
break;
case 2:
list_count = DictionaryIterator(App.Parser.QuotesBookAboutArrayList);
if (list_count > 0)
this.Quotes.Add(new ItemViewModel() { LineOne = StringResource.QuotesAboutBook });
break;
case 3:
list_count = DictionaryIterator(App.Parser.QuotesBookFromArrayList);
if (list_count > 0)
this.Quotes.Add(new ItemViewModel() { LineOne = StringResource.QuotesFromBook });
break;
case 4:
list_count = DictionaryIterator(App.Parser.QuotesReaderAboutArrayList);
if (list_count == 1)
this.Quotes.Add(new ItemViewModel() { LineOne = StringResource.QuotesAboutReader });
else if (list_count > 1)
this.Quotes.Add(new ItemViewModel() { LineOne = StringResource.QuotesAboutReaders });
break;
case 5:
list_count = DictionaryIterator(App.Parser.QuotesReaderFromArrayList);
if (list_count == 1)
this.Quotes.Add(new ItemViewModel() { LineOne = StringResource.QuotesFromReader });
else if (list_count > 1)
this.Quotes.Add(new ItemViewModel() { LineOne = StringResource.QuotesFromReaders });
break;
}
}
}
Basically this happens because your code is locking up the UI thread. And the reason it locks it up, is because it's way to slow.
And looking at your code now, it's a crazy amount of work you're doing in what should be a simple data loading from the isolated storage. You need to move all this UI work over to the View, and first handle it upon creation of the actual view, not before, as you're doing right now.
Personally I dislike the idea of coupling the viewmodel with your App class, and I also think it's pointless to use the Application_Activated/Deactivated for tombstoning, rather than handling persistence at OnNavigatedFrom and OnNavigatedTo.
I think it'll be difficult to give a precise answer to what is causing the problem, but my guess right now lies in that you're using the process for the tombstoning to re-create the UI, instead of letting the UIThread itself do the work.
The whole part about you're generating the UI in C# is just so plain wrong as it can be. XAML is made for this, and it's really good at what it's made for.
Are you sure that you're only restoring state if the code was actually tombstoned?
I suspect that you're coming back to your app before it is tombstoned but still trying to restore state. Quite what you're saving and how you restore it will determine how you can check if you need to restore it. Checking for null or if not the defautl value is probably the easiest way.
You may also get better performance if you only save the state of anything you absolutely have to. You should also try saving the State in the OnNavigatingFrom event, rather than the OnNavigatedFrom event.
What and how are you saving to IS?
Why not use the Page.State object?

Program to generate Tables, trouble using Events

I am doing a program in C# for kids with which kids can test their knowledge of Multiplication tables.
I cannot get the value of 'i' in the Result_Leave() function to track which value of the text box array is incorrect.
For Example:
5 X 1 = [ ] <---- an array of textboxes with name Result[i]"
the user enters the value of 5*1 in the text box and my program instantly checks if the entered value is correct or not, using the "Leave" event for the text box.
I have used an array of text boxes...
So I cannot track which Result[i] contains the incorrect value...
I have fired the function "Result_Leave" for each of the text boxes "Result[i]"
Here is the code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Tables
{
public partial class FormMain : Form
{
private System.Windows.Forms.Label[] labelNumber;
private System.Windows.Forms.Label[] labelCross;
private System.Windows.Forms.Label[] labelTableOf;
private System.Windows.Forms.Label[] labelEquals;
/*"Result" is an array of textboxes which takes the result of the multiplication from the user*/
private System.Windows.Forms.TextBox[] Result; //declaration
public FormMain()
{
InitializeComponent();
WindowState = FormWindowState.Maximized;
buttonCheckAnswers.Enabled = false;
}
private void buttonGo_Click(object sender, EventArgs e)
{
if (textBoxInput.Text == "")
{
errorProvider1.SetError(textBoxInput, "Hey! Enter a number please");
}
else
{
textBoxInput.Enabled = false;
buttonCheckAnswers.Enabled = true;
labelNumber = new System.Windows.Forms.Label[10];
labelCross = new System.Windows.Forms.Label[10];
labelTableOf = new System.Windows.Forms.Label[10];
labelEquals = new System.Windows.Forms.Label[10];
Result = new System.Windows.Forms.TextBox[10];
for (int i = 0; i < 10; i++)
{
// this snippet generates code for adding controls at runtime viz. textboxes and labels
labelNumber[i] = new Label();
this.labelNumber[i].AutoSize = true;
this.labelNumber[i].Location = new System.Drawing.Point(200, 163 + 55 * i);
this.labelNumber[i].Name = "labelNumber";
this.labelNumber[i].Size = new System.Drawing.Size(35, 13);
this.labelNumber[i].Text = (i + 1).ToString();
this.labelNumber[i].Font = new System.Drawing.Font("Comic Sans MS", 17F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.labelNumber[i].ForeColor = System.Drawing.Color.Khaki;
this.Controls.AddRange(new System.Windows.Forms.Control[] { labelNumber[i] });
labelCross[i] = new Label();
this.labelCross[i].AutoSize = true;
this.labelCross[i].Location = new System.Drawing.Point(150, 163 + 55 * i);
this.labelCross[i].Name = "labelCross";
this.labelCross[i].Size = new System.Drawing.Size(35, 13);
this.labelCross[i].Text = "X";
this.labelCross[i].Font = new System.Drawing.Font("Comic Sans MS", 17F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.labelCross[i].ForeColor = System.Drawing.Color.Khaki;
this.Controls.AddRange(new System.Windows.Forms.Control[] { labelCross[i] });
labelTableOf[i] = new Label();
this.labelTableOf[i].AutoSize = true;
this.labelTableOf[i].Location = new System.Drawing.Point(100, 163 + 55 * i);
this.labelTableOf[i].Name = "labelTableOf";
this.labelTableOf[i].Size = new System.Drawing.Size(35, 13);
this.labelTableOf[i].Text = textBoxInput.Text;
this.labelTableOf[i].Font = new System.Drawing.Font("Comic Sans MS", 17F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.labelTableOf[i].ForeColor = System.Drawing.Color.Khaki;
this.Controls.AddRange(new System.Windows.Forms.Control[] { labelTableOf[i] });
labelEquals[i] = new Label();
this.labelEquals[i].AutoSize = true;
this.labelEquals[i].Location = new System.Drawing.Point(250, 163 + 55 * i);
this.labelEquals[i].Name = "labelTableOf";
this.labelEquals[i].Size = new System.Drawing.Size(35, 13);
this.labelEquals[i].Text = "=";
this.labelEquals[i].Font = new System.Drawing.Font("Comic Sans MS", 17F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.labelEquals[i].ForeColor = System.Drawing.Color.Khaki;
this.Controls.AddRange(new System.Windows.Forms.Control[] { labelEquals[i] });
/*"Result" is an array of textboxes which takes the result of the multiplication from the user*/
Result[i] = new TextBox();
this.Result[i].BackColor = System.Drawing.Color.BlueViolet;
this.Result[i].Font = new System.Drawing.Font("Comic Sans MS", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.Result[i].ForeColor = System.Drawing.SystemColors.Info;
this.Result[i].Location = new System.Drawing.Point(300, 163 + 55 * i);
this.Result[i].Name = "Result" + i;
this.Result[i].Size = new System.Drawing.Size(57, 37);
this.Result[i].TabIndex = i;
/*this is where the problem arises...*/
this.Result[i].Leave += new System.EventHandler(this.Result_Leave);// how do I send the value of 'i' to Result_Leave() function
/*Note - Result_Leave() is FIRED when the cursor moves away from the "Result" textbox*/
this.Controls.AddRange(new System.Windows.Forms.Control[] { Result[i] });
}
}
}
private void textBoxInput_TextChanged(object sender, EventArgs e)
{
errorProvider1.Clear();
}
private void radioButtonInstantChecking_CheckedChanged(object sender, EventArgs e)
{
if (radioButtonCheckAtLast.Checked == true && textBoxInput.Text!="")
{
buttonCheckAnswers.Enabled = true;
}
else buttonCheckAnswers.Enabled = false;
}
private void Result_Leave(object sender, EventArgs e)
{
/*Code for checking multiplication goes here*/
/*If multiplication result entered by the user is
*correct change the background colour of the corresponding textbox "Result[i] to GREEN else BLUE"
*as in buttonCheckAnswers_Click() function...
*/
}
private void textBoxInput_KeyPress(object sender, KeyPressEventArgs e)
{
if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar) && e.KeyChar != '.')
{
e.Handled = true;
}
// only allow one decimal point
if (e.KeyChar == '.' && (sender as TextBox).Text.IndexOf('.') > -2)
e.Handled = true;
}
private void buttonCheckAnswers_Click(object sender, EventArgs e)
{
int score=0;
bool flag=false;
for (int i = 0; i < 10; i++)
{
if (Result[i].Text == "")
{
flag = true;
break;
}
else if ((Convert.ToInt32(Result[i].Text)) != ((Convert.ToInt32(labelNumber[i].Text) * (Convert.ToInt32(labelTableOf[i].Text)))))
{
Result[i].BackColor = System.Drawing.Color.Red;
}
else
{
Result[i].BackColor = System.Drawing.Color.Green;
score += 1;
}
}
if (score == 10)
labelComments.Text = "Well done kid! Full Marks!\nYou know your table of\n"+textBoxInput.Text+" very well"+"\nScore = "+score;
else if(flag)
labelComments.Text = "Oops! \nComplete your table kid!";
else
labelComments.Text = "Oops! \nThere are errors. \nPlease revise your tables!" + "\nYour score is : " + score;
}
}
}
One quick-and-dirty way to do this is to set a value in each TextBox's Tag property. In the for loop inside buttonGo_Click, you could set Result[i].Tag = i;, then in Result_Leave you could do:
int number = (int)((sender as TextBox).Tag);

Resources