Application settings do not allways save - c#

I have a bit of a Heisenbug. I have a list of what was recently searched for sometimes it will save the history some times it does not. When I attach the debugger and step through StartFind() it works every time.
public Form1()
{
oldClinicsBindingSource.DataSource = ContractFlowTool.Properties.Settings.Default.RecentClinics;
}
private void StartFind()
{
(...)
if (oldClinicsBindingSource.Contains(newClinic))
oldClinicsBindingSource.Remove(newClinic);
oldClinicsBindingSource.Insert(0, newClinic);
oldClinicsBindingSource.EndEdit();
while (ContractFlowTool.Properties.Settings.Default.NumberOfClinicsToRemember < oldClinicsBindingSource.Count)
{
oldClinicsBindingSource.RemoveAt(oldClinicsBindingSource.Count - 1);
}
ContractFlowTool.Properties.Settings.Default.Save();
(..)
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{ //Breakpoint on this line
ContractFlowTool.Properties.Settings.Default.Save();
}
//In Settings.Designer.cs
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public global::System.Collections.ArrayList RecentClinics {
get {
return ((global::System.Collections.ArrayList)(this["RecentClinics"]));
}
set {
this["RecentClinics"] = value;
}
}
If I put a breakpoint on the { before the save inside Form1_FormClosing then hit continue (I don't even step over) it saves correctly. If the breakpoint is not there it does not save.
The program does use background workers in other parts but they not being run in my test case case.
Any help would be greatly appreciated.

Commenting out the Save() inside StartFind() appears to have fixed it.
I am still curious why it was happening. Do binding sources use internal threading?

Related

Xamarin iOS app freezes: ViewDidAppear() never gets called

This seems to be a tricky one:
We're working on a Xamarin iOS app that has a UITableView control displaying a list of profiles. Once the user clicks on one of the profiles we'd like to switch to a separate "ProfileViewController" to display more detailed information. This works just fine for 99.9% of the time. In the remaining ~0.1% the item in the list gets highlighted (which happens OnClick) but the app just seemingly freezes and never switches to the other ViewController, leaving the user with an unresponsive list.
The interesting thing to note here is that the app doesn't really freeze, as the simple "swipe back" gesture brings the user back to the UITableView (to be clear the switch-to-profile-viewcontroller animation is never played so it basically switches from the unresponsive list back to the same list, but now it is responsive again).
The tricky thing is that we can't reliably reproduce this bug. It just seems to happen at random, sometimes while stuff is running in the background, other times while the app was previously in an idle state. We are pretty sure that it isn't related to multithreading (we triple-checked everything, using locking and semaphores where necessary), it rather seems to be some rendering issue (as you can still swipe back to the previous screen or at least it isn't your common dead lock).
Using a bunch of Console.WriteLine() tracers and hours of trial and error reproducing this bug we could isolate the problem and discovered the following:
Upon clicking on the list code in ViewDidLoad() and ViewWillAppear() is successfully executed. However ViewDidAppear() never gets invoked. There is nothing else happening in our code or on different threads between ViewWillAppear() and ViewDidAppear() and we don't have any funky / unusual code that gets executed previously (just the usual UI initialization like this in ViewDidLoad()):
...
LblProfileName.TextAlignment = UITextAlignment.Center;
LblProfileName.Text = string.Empty;
LblProfileName.Font = FontAgent.ForSize(30);
LblProfileSlogan.TextAlignment = UITextAlignment.Center;
LblProfileSlogan.Text = string.Empty;
LblProfileSlogan.Font = FontAgent.ForSize(20);
LblProfileRelationInfo.TextAlignment = UITextAlignment.Center;
LblProfileRelationInfo.Text = string.Empty;
LblProfileRelationInfo.Font = FontAgent.ForSize(15);
...
At this point we are kinda out of ideas as to what could be going wrong here and we have independently reviewed any of our code that could remotely be involved in this bug but we found nothing.
We didn't find anything related online but maybe someone else has encountered a similar issue like this in Xamarin / Xamarin iOS before?
Are there any steps we could take that we don't know of? When breaking the app in the Visual Studio for Mac debugger during the freezes the call stacks only contain native code and are not of much use.
Any help or ideas as to what else we could try are hugely appreciated :)
Edit: Adding some code
This is our BaseViewController defining some initialization methods to be used by it's children (again in 99.9% of all cases this works just fine):
public abstract class BaseViewController : UIViewController
{
public BaseViewController(string nibName, NSBundle nSBundle) : base(nibName, nSBundle)
{
ControllerDidInitialize();
}
public ClubmappViewController(IntPtr handle) : base(handle)
{
ControllerDidInitialize();
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
CustomOrientationService.ScreenRotationPortrait();
InitializeStaticContent();
Console.WriteLine("ViewDidLoad() exits just fine...");
}
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
Console.WriteLine("When the bug occurs this never gets executed :C");
RefreshUI();
OnViewDidAppear?.Invoke(this, new EventArgs());
LoadData();
}
private protected abstract void InitializeStaticContent();
private protected abstract void RefreshUI();
private protected virtual void LoadData()
{
}
private protected virtual void ControllerDidInitialize()
{
}
}
This is the ProfileViewController that inherits from BaseViewController and that just stops being rendered or inititialized or whatever the actual problem might be (it just never shows up as described above) but most of the time it works just fine:
public partial class ProfileViewController : BaseViewController
{
public const string STORYBOARD_ID = "ProfileViewController";
public ProfileViewController(IntPtr handle) : base(handle)
{
}
private protected override void ControllerDidInitialize()
{
// do initialization things like initializing variables, etc
// no real logic here
}
private protected override void InitializeStaticContent()
{
// layouting loading
LblProfileTitle.TextAlignment = UITextAlignment.Center;
LblProfileTitle.Text = string.Empty;
LblProfileTitle.Font = FontAgent.ForSize(20);
LblProfileTitle.Font = UIFont.BoldSystemFontOfSize(20);
LblProfileName.TextAlignment = UITextAlignment.Center;
LblProfileName.Text = string.Empty;
LblProfileName.Font = FontAgent.ForSize(30);
LblProfileSlogan.TextAlignment = UITextAlignment.Center;
LblProfileSlogan.Text = string.Empty;
LblProfileSlogan.Font = FontAgent.ForSize(20);
// ... and so on ..
}
private protected override void RefreshUI()
{
// ... theme related stuff ...
ViewProfileActive.BackgroundColor = ThemeAgent.CurrentTheme.OnlineIndicatorColor;
LblProfileName.TextColor = ThemeAgent.CurrentTheme.PrimaryTextColor;
LblProfileSlogan.TextColor = ThemeAgent.CurrentTheme.SecondaryTextColor;
// ...
}
private protected async override void LoadData()
{
// load user data ...
ProfileData data = await ...
}
}
And this is the "OnClick" event that is triggered when a profile is clicked on, that's supposed to initialize and show the ProfileViewController (it's unlikely that something's wrong with this but including it nonetheless):
// ...
(sender, e) =>
{
ProfileViewController profileController = (ProfileViewController)UIStoryboard.FromName("Main", null).InstantiateViewController(ProfileViewController.STORYBOARD_ID);
profileController.ModalPresentationStyle = UIModalPresentationStyle.FullScreen;
currentViewController.NavigationController.PushViewController(profileController, true);
}
// ...

Why isn't this causing an infinite loop of events?

I have a simple application that reverses any text typed to it in another textbox. The catch is, you can modify either textbox and the changes will be (literally) reflected in the other.
I wrote this code, believing for it to cause problems.
private void realText_TextChanged(object sender, EventArgs e)
{
mirrorText.Text = mirror(realText.Text);
}
private void mirrorText_TextChanged(object sender, EventArgs e)
{
realText.Text = mirror(mirrorText.Text);
}
private string mirror(string text)
{
return new string(text.Reverse().ToArray()).Replace("\n\r", "\r\n");
}
I then tried it out, believing that it would cause an infinite loop (realText changes mirrorText, another event happens, mirrorText changes realText, etc). However, nothing except the intended behavior happened.
I'm of course happy about this, I could just leave it here. Or could I?
I'm quite sure the TextChanged event is supposed to be fired whenever Text is changed. Is this intended behavior of some error protection in the events, or was I just lucky? Can this code misbehave on another computer, with other build settings, etc? It can be easily fixed:
private void realText_TextChanged(object sender, EventArgs e)
{
if (realText.Focused)
{
mirrorText.Text = Mirror(realText.Text);
}
}
I'll probably do it anyway to be safe, but is it required to check this? (I'm not even going to ask if it's recommended.)
Per the comments, and as already answered, the TextChanged event is not getting raised when you set the Text property to the value it already has.
It's not clear whether this is something you can safely rely upon. It is a sensible optimisation, and I would be very surprised if future versions of .NET Framework drop it, but I cannot speak for older versions, nor for third-party implementations (Mono).
To be absolutely safe, I would not use the Focused check you put in your question. I would do exactly what the Text setter does now.
private void realText_TextChanged(object sender, EventArgs e)
{
var newMirrorText = Mirror(realText.Text);
if (mirrorText.Text != newMirrorText)
mirrorText.Text = newMirrorText;
}
This has the same advantage of preventing infinite recursion, but plays more nicely with other code you may put in your form that changes the text as a result of some other event.
The reason it doesn't cause a loop is that it checks whether the Text property actually changed, i.e. if the new value does not equal the old value. In your case the mirror function happens to reverse itself, which leads to the same text after two passes.
It's pretty easy to check.
First, replace both textbox controls with
class T : TextBox
{
public override string Text
{
get
{
return base.Text;
}
set
{
base.Text = value;
}
}
}
Second, set the breakpoint on setter. Add these expressions to the Watch window:
Name
Text
value
Third, launch the app, copy '123' from somewhere and paste it to the first textbox. Here it goes:
1st break:
Name: "mirrorText"
Text: ""
value: "321"
2nd break:
Name: "realText"
Text: "123"
value: "123"
3rd... whoops, it does not breaks anymore. To detect why we had to go deeper. Look at referencesource: text box setter does nothing unusual, but TextBoxBase's one looks interesting:
set {
if (value != base.Text) { // Gotcha!
base.Text = value;
if (IsHandleCreated) {
// clear the modified flag
SendMessage(NativeMethods.EM_SETMODIFY, 0, 0);
}
}
}
So, as hvd already answered, the reason is the textbox does not raise TextChanged if old and new values are the same. I don't think the behavior will change, at least for winforms. But if you want more robust solution, here it is:
private void RunOnce(ref bool flag, Action callback)
{
if (!flag)
{
try
{
flag = true;
callback();
}
finally
{
flag = false;
}
}
}
private bool inMirror;
private void realText_TextChanged(object sender, EventArgs e)
{
RunOnce(ref inMirror, () =>
{
mirrorText.Text = mirror(realText.Text);
});
}
private void mirrorText_TextChanged(object sender, EventArgs e)
{
RunOnce(ref inMirror, () =>
{
realText.Text = mirror(mirrorText.Text);
});
}
private string mirror(string text)
{
return new string(text.Reverse().ToArray()).Replace("\n\r", "\r\n");
}
P.S. mirror() will fail on surrogate pairs. Here're some solutions.
If textbox has a Text, and we try to change it with the same Text, the TextChange event is not raising because new text is same as the previous.
In your code, the realText_TextChanged event reverses the text and changes the mirrorText with it.
The mirrorText_TextChanged event reverses the text and try to change the realText.
The realText has already this text and does not raises the realText_TextChanged event.

How to display data received from serial port in a textbox without the text disappearing in Visual Studio C#?

So, I'm trying to develop a simple application in visual C# which gets data from serial port and displays it in a textbox (to monitor temperature). I'm acquiring and displaying the data successfully, using the DataReceived event to update a global string variable and a timer to update the text field on my text box, as shown:
private void port_DataReceived_1(object sender, SerialDataReceivedEventArgs e)
{
try
{
globalVar.updateTemp = port.ReadLine(); //This is my global string
}
catch (IOException)
{
}
catch (InvalidOperationException)
{
}
catch (TimeoutException)
{
}
}
private void timer1_Tick(object sender, EventArgs e)
{
tempDisplayBox.Text = globalVar.updateTemp; //This is my textbox updating
}
The only issue I have is that the value shown in the textbox keeps flashing, making it hard to read. My timer is set to trigger every 10 ms (which should be fast enough, right?). Is there any way to make it more stable? I realize this may be a newb question, but to be fair I am a newb :) Any help is appreciated! Thanks!
Do you really need it updating every 10ms? What about every 500 ms or if not that then 100ms. 100ms will require your update method run 10 times less and therefore update 10 times less. The flickering you are expiriencing is due to the refresh speed. You could create custom method which will only update the temp only when target Label or textBox value is different than source port. But that will only sort the flickering when temp is steady, when temp will start vary it will bring back the flickering. Good luck ;-)
UPDATE
Hi I tried to reproduce the conditions and could not make my textbox nor Label flash. The way I tested it was by assigning int ntick = 0; and then increment the ++ntick; inside of the timer_tick method. The results didn't make any of the controls flash and were updated even every milisecond at some point. I also tried string.Format to put some load on the method. Is your app responsive?
The trick is to use double buffering. This way the operating system will redraw the Control off-screen, and only show the control when it is fully redrawn.
I have had the same problem, and solved it by extending the TextBox control like this:
public FastLogBox()
{
InitializeComponent();
_logBoxText = new StringBuilder(150000);
timer1.Interval = 20;
timer1.Tick += timer1_Tick;
timer1.Start();
SetStyle(ControlStyles.DoubleBuffer, true);
}
void timer1_Tick(object sender, EventArgs e)
{
if (_timeToClear)
{
_logBoxText.Clear();
_timeToClear = false;
}
if (_logQueue.Count <= 0) return;
while (!_logQueue.IsEmpty)
{
string element;
if (!_logQueue.TryDequeue(out element)) continue;
{
_logBoxText.Insert(0, element + "\r\n");
}
}
if (_logBoxText.Length > 150000)
{
_logBoxText.Remove(150000, _logBoxText.Length - 150001);
}
Text = _logBoxText.ToString();
}
public new void Clear()
{
_timeToClear = true;
while (!_logQueue.IsEmpty)
{
string element;
_logQueue.TryDequeue(out element);
}
}
public void AddToQueue(string message)
{
_logQueue.Enqueue(message);
}
}
I also use a timer and a concurrentQueue to avoid using Invoke to update the control from another thread. I also use a StringBuilder to prepare the string before putting it into the TextBox. StringBuilder is faster when building larger strings.
You can use ReadExisting() to read the whole data at a time.
You need to handle DataReceived Event of SerialPort
serialPort1.ReadExisting();
Sample:
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
String myData=serialPort1.ReadExisting();
}
Example Code: Here i would like to show you the code to Read Data(RFID Tag Code which is basically of length 12)
String macid = "";
private void DoWork()
{
Invoke(
new SetTextDeleg(machineExe ),
new object[] { macid });
macid = "";
}
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
string str1;
macid += serialPort1.ReadExisting();
if (macid.Length == 12)
{
macid = macid.Substring(0, 10);
Thread t = new Thread(new ThreadStart(DoWork));
t.Start();
}
}
public void machineExe(string text)
{
TextBox1.Text=text;
}
Thank you so much for the answers! I found a way to work around this issue:
Instead of replacing the contents of my textbox by rewriting the TextBox.Text property - which, as HenningNT implied, refreshes the control and causes the flickering - I'm now using the TextBox.AppendText method. Though, as I want to display only one line of data at a time, I use the textbox in multiline mode and the Environment.NewLine to jump to a new line before appending the text. As for the method of updating, I've gone back to using the timer because with the invoke method was crashing my application when I close the form, for some reason. Also, enabling double buffering didn't do me much good, although I guess I was doing it wrong... It still flickers a bit, but it's much better now :) I know this is not really a perfect solution (much more of a workaround), so I'll keep looking for it. If I find it, I'll be sure to update it here ;) My code:
private void timer1_Tick(object sender, EventArgs e) //Timer to update textbox
{
if (tempDisplayBox.Text != globalVar.updateTemp) //Only update if temperature is different
{
try
{
tempDisplayBox.AppendText(Environment.NewLine);
tempDisplayBox.AppendText(globalVar.updateTemp);
}
catch (NullReferenceException)
{
}
}
}

Get and Set not being called

So I have a couple fields in a program that set the email subject and email body for an automated message.
My Email Settings class is this:
public static class Email
{
public static string Body
{
get { return (string) SettingsStore.RetrieveSettingValue("emailBody"); }
set { SettingsStore.StoreSetting(new Setting {SettingKey = "emailBody",
SettingValue = value}); }
}
public static string Subject
{
get { return (string) SettingsStore.RetrieveSettingValue("emailSubject"); }
set { SettingsStore.StoreSetting(new Setting {SettingKey = "emailSubject",
SettingValue = value}); }
}
}
And my UI code that gets and sets the values is here:
private void ApplicationSettings_Load(object sender, EventArgs e)
{
subjectTextEdit.Text = Settings.Email.Subject;
bodyTextEdit.Text = Settings.Email.Body;
}
private void ApplicationSettings_FormClosing(object sender, FormClosingEventArgs e)
{
Settings.Email.Subject = subjectTextEdit.Text;
Settings.Email.Body = bodyTextEdit.Text;
}
Oddly, my get and set methods in the Email Settings class are not being called- when I access this form for the first time after application start the fields are blank even when the values are in the database. After I edit the fields once and close that form then open the form again (without closing the entire application) the fields have the text I put into them.
I have set a breakpoint on the _Load and _FormClosing events and these are getting hit.
When I set a breakpoint on the get/set methods inside the settings class, the breakpoints are not getting hit.
Any ideas?
To everyone: Thanks for your help, I found the issue- the issue was Visual Studio, not the code.
I closed VS, restarted the PC, opened VS, cleaned the solution, closed, reopened, built. There was an error in one of my referenced assemblies that was not appearing all the other times I built the project that appeared this time, and fixing that error caused all of this to work properly.
I'd have never found this without your help (I'd still be scratching my head wondering how my code was wrong) so thank you all so much! :)

Saving String values for Tombstoning

I'm currently developing an app for Windows Phone 7.1, and need to save some data for when the user quits the app.
The app is pretty straightforward: the MainPage is the first thing the user sees, in which they select one of four shopping centers. The next page asks them where they have parked their car and stores it as a String variable. The last page loads that String variable and displays back to the user the relevant information, along with a timer that has been ongoing since launching the app.
What I want to save is the user-input data and the timer value when the user leaves the app, so that when launching it again, it automatically shows the last page with the user's info in it.
I've been playing around with the generated Application_Launching, Activated, etc events, but so far can't get something to work. Any help would be greatly appreciated.
Edit: Here's some code that I have so far (hasn't led me anywhere)
void LoadSettings()
{
IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings;
String mall;
String level;
String letter;
String number;
if (settings.TryGetValue<String>("mall", out mall))
{
_mall = mall;
}
if (settings.TryGetValue<String>("level", out level))
{
_level = level;
}
if (settings.TryGetValue<String>("mall", out letter))
{
_letter = letter;
}
if (settings.TryGetValue<String>("mall", out number))
{
_number = number;
}
}
void SaveSettings()
{
IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings;
if (_mall != null)
{
settings["mall"] = (_mall as String);
settings["level"] = (_level as String);
settings["letter"] = (_letter as String);
settings["number"] = (_number as String);
}
}
That's in my App.xaml.cs class
You have to look at the events in your app.cs file, but it also depends on what you want when tha application is Activated, Deactived, Closed and launched.
// Code to execute when the application is launching (eg, from Start)
// This code will not execute when the application is reactivated
private void Application_Launching(object sender, LaunchingEventArgs e)
{
LoadSettings();
}
// Code to execute when the application is activated (brought to foreground)
// This code will not execute when the application is first launched
private void Application_Activated(object sender, ActivatedEventArgs e)
{
if (e.IsApplicationInstancePreserved)
{
//The application was dormant and state was automatically preserved
}
else
{
LoadSettings();
}
}
// Code to execute when the application is deactivated (sent to background)
// This code will not execute when the application is closing
private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
SaveSettings();
}
// Code to execute when the application is closing (eg, user hit Back)
// This code will not execute when the application is deactivated
private void Application_Closing(object sender, ClosingEventArgs e)
{
SaveSettings();
}

Categories

Resources