I'm trying to save two Lists of objects in the phone ApplicationSettings, but I'm stuck at a strange issue (But it's probably me making a silly mistake somewhere).
If I only save one of the lists, it works as supposed - It'll save it, and reload it when app is launched next time.
But if I try to save 2 lists, none of them seem to be saved correctly. No errors or anything, just "blankness".
See code below.
//My save method
public void Gem()
{
var settings = IsolatedStorageSettings.ApplicationSettings;
if (settings.Contains(INDTASTNINGER_LIST))
{
settings[INDTASTNINGER_LIST] = _indtastningsListe;
}
else
settings.Add(INDTASTNINGER_LIST, _indtastningsListe);
if (settings.Contains(INDTASTNINGER_LIST2))
{
settings[INDTASTNINGER_LIST2] = _indtastningsListe2;
}
else
settings.Add(INDTASTNINGER_LIST2, _indtastningsListe2);
settings.Save();
}
//Constructor supposed to load settings
public Indtastninger()
{
var settings = IsolatedStorageSettings.ApplicationSettings;
if (settings.Contains(INDTASTNINGER_LIST))
{
_indtastningsListe = null;
_indtastningsListe = (List<Indtastning>)settings[INDTASTNINGER_LIST];
}
if (settings.Contains(INDTASTNINGER_LIST2))
{
_indtastningsListe2 = null;
_indtastningsListe2 = (List<Indtastning>)settings[INDTASTNINGER_LIST2];
}
}
What am I doing wrong?
If I comment out the part with "list2" stuff, the first one will be saved/retrieved perfectly.
I have faced the same issue some time ago, the problem is that you only can save on the IsolatedStorage objects that are XML serializables.
if you save other object, it will work even with the debugger but when the app is restarted, all the saved data is lost.
Related
For my latest WPF application, I've been using an System.Collections.Specialized.StringCollection to save and load strings. My current system works like a charm in Debug and Release, but when deployed to ClickOnce, the application crashes as soon as anything involving the settings are involved (loading or saving)! However, System.Collections.Specialized.StringCollections work just fine on their own if not a setting.
What could be causing these crashes?
Here are my systems:
public static void SaveCharacter(string code)
{
// Declare a blank StringCollection
StringCollection strings = new StringCollection();
// Convert the current settings StringCollection into an array and combine with the blank one
if (Settings.Default.SavedCharacters.Count > 0)
{
string[] tempArr= new string[Settings.Default.SavedCharacters.Count];
Settings.Default.SavedCharacters.CopyTo(tempArr, 0);
strings.AddRange(tempArr);
}
// Add the new string to the list
strings.Add(code);
// This new list is now saved as the setting itself
Settings.Default.SavedCharacters = strings;
Settings.Default.Save();
}
public static void RestoreCharacters()
{
foreach (string str in Settings.Default.SavedCharacters)
{
CreateCharacter(str, "l" + ID.ToString()); // This function works fine
ID++; // So does this variable (it's a public static)
}
}
P.S. I tried a similar system with List<string> items, but no dice. Other settings involving strings, bools and ints work fine though.
P.P.S. Sidenote, does anyone know how to combine System.Collections.Specialized.StringCollections without having to convert one to an array?
Answering my own question in case anyone else gets stuck with such an annoying bug! Before you can operate on a User Setting that has to be newed(), you need to create an instance of it to utilise instead. For example:
StringCollection foo = Settings.Default.SavedCharacters;
When it comes to saving such collections, simply using Settings.Default.SavedCharacters = foo; works fine!
I'm working on a simple portfolio project. I would like to show images on a webpage that logged in users can edit. My problem is in the [HttpPost] Edit, more specifically this part:
if (ModelState.IsValid)
{
//updating current info
inDb = ModelFactory<ArtSCEn>.GetModel(db, artSCEn.ArtSCEnID);
inDb.LastModified = DateTime.Now;
inDb.TechUsed = artSCEn.TechUsed;
inDb.DateOfCreation = artSCEn.DateOfCreation;
inDb.Description = artSCEn.Description;
inDb.ArtSC.LastModified = DateTime.Now;
//validating img
if (Validator.ValidateImage(img))
{
inDb.ImageString = Image.JsonSerialzeImage(img);
}
else
{
//return to the UI becuase we NEED a valid pic
return View(artSCEn);
}
db.Entry(inDb).State = System.Data.Entity.EntityState.Modified;
db.SaveChanges();
//[PROBLEMATIC PART STARTS HERE]
//updating the pic on the server
//getting the string info
string userArtImgFolder = Server.MapPath($"~/Content/Images/Artistic/{inDb.ArtSC.PersonID}");
string imgNameOnServer = Path.Combine(
userArtImgFolder,
$"{inDb.ArtSC.PersonID}_{inDb.ArtSC.ArtSCID}_{inDb.ArtSCEnID}{Path.GetExtension(img.FileName)}");
//deleting previous pic
System.IO.File.Delete(imgNameOnServer);
//creating a new pic
Image.ResizePropotionatelyAndSave(img, Path.Combine(
userArtImgFolder,
$"{inDb.ArtSC.PersonID}_{inDb.ArtSC.ArtSCID}_{inDb.ArtSCEnID}{Path.GetExtension(img.FileName)}"));
return RedirectToAction("Edit", "Art", new { id = inDb.ArtSCID });
}
When I get back the new picture and I want to delete the previous, System.IO.File.Delete() always triggers an exception that it cannot access the resource, because someone else is holding onto it. Any idea what that might be?
Maybe it's something simple, I'm new to ASP, but just can't figure it out.
UPDATE
Following on the suggestions in the comments section, I checked the processes with a tool called Process Monitor and it seems that indeed IIS is locking the resource:
This one appears 2 more times in the logs, by the way.
Judging by the fact that the operation is CreateFileMapping, I guess it has to do with either Server.MapPath() or Path.Combine(), however, the Server is an IDisposable (being derived from Controller), so can that be the one I should deal with?
Also, the resource I'm trying to delete is an image used on the website, which might be a problem, but that section of the website is not shown during this process.
I found the solution building on the comment of #Diablo.
The IIS was indeed holding on to the resource, but Server.MapPath() or any of that code had nothing to do with it: it was the Edit view my page returning the data to. With the help of this SO answer, it turns out I was careless with a BitMap that I used without a using statement in the view to get some image stats. I updated the helper function with the following code:
public static float GetImageWidthFromPath(string imgAbsolutPath, int offset)
{
float width = 0;
using (Bitmap b = new Bitmap(imgAbsolutPath))
{
width = b.Width - offset;
}
return width;
}
Now IIS does not hold on to the resource and I can delete the file.
I'm making an educational game (Windows 10 UWP, C# + XAML) and I need to store user information (in particular, their current score) and retrieve it when they start the app again. I've found a way to do this (see code below) but I have no idea if this is a normal solution to this problem. I'm currently creating a txt file and storing and retrieving data in/from it. Are there more common, or simpler ways to do this?
Here's what I'm currently doing:
Create the file:
StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
StorageFile sampleFile = await storageFolder.CreateFileAsync("nameOfTextFile.txt", CreationCollisionOption.OpenIfExists); //other options are ReplaceExisting
Open the file:
StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
StorageFile sampleFile = await storageFolder.GetFileAsync("nameOfTextFile.txt");
Write text to the file:
await FileIO.WriteTextAsync(sampleFile, "Put the added text here");
Read text from the file:
string someVariableName = await FileIO.ReadTextAsync(sampleFile);
-Thanks in advance for any help!!
While the file-based approach is valid, there are easier ways, at least for simple data: You can use roaming (or local) settings. Roaming settings are roamed between devices, as long as their size don't exceed 64K, and would carry the score from the user's desktop to the user's phone, for example. Local settings stay on the machine.
Settings are easy to use:
IPropertySet propertySet = ApplicationData.Current.RoamingSettings.Values;
// Get previous score (or 0 if none)
int score = (int)(propertySet["Score"] ?? 0);
// ...play game...
// Set updated score:
propertySet["Score"] = score;
The way I go about doing projects and settings like this is creating a propery setting in Visual Studio, then Setting and Getting the setting / Value.
You can access this by going to the application properties.
This allows access to read,write, and save information / onload restore information.
Some Informational Links:
https://msdn.microsoft.com/en-us/library/bb397755(v=vs.110).aspx
and (Suggested)
https://msdn.microsoft.com/en-us/library/aa730869(v=vs.80).aspx
OK, so here goes an example of using a class to store your settings in.
There are many, many more ways you could do this. Too many to list.
Create a settings class:
public class YourSettingsClass
{
public string UserFirstName { get; set; }
public string UserLastName { get; set; }
public string UserScore { get; set; }
}
Create an AppSettings helper
public AppSettings
{
private static YourSettingsClass _settings = new YourSettingsClass();
public static string UserFirstName
{
get { return _settings.UserFirstName; }
set { _settings.UserFirstName = value; }
}
public static string UserLastName
{
get { return _settings.UserLastName; }
set { _settings.UserLastName = value; }
}
public static string UserScore
{
get { return _settings.UserScore; }
set { _settings.UserScore = value; }
}
public static void SaveSettings()
{
// Now, use your "settingsfile.xml" (or whatever you're saving as)
// to write your settings to from your _settings static field object.
// I'll let you have a play as to how you want to do this...
}
public static void LoadSettings()
{
YourSettingsClass tempSettingsClass = new YourSettingsClass();
// Now, use your "settingsfile.xml" (or whatever you've saved it as)
// to load in your settings and assign to your tempSettingsClass variable.
// I'll let you have a play as to how you want to do this...
// Assign the settings from your loaded object.
_settings = tempSettingsClass;
}
}
Now, from any other class, you can call AppSettings.LoadSettings(). You could do this on App Startup, or on-demand.
When you've loaded the settings in, just reference AppSettings.UserFirstName or whatever property you want to either get the value or set the value.
When you're ready to, you can then save the settings back to the XML file on disk, through AppSettings.SaveSettings().
I've purposely omitted the code for loading and saving from the storage, and for se/deserializing class objects as I haven't got any UWP components on this PC and I've done this all from memory so I don't want to put anything in to throw you off.
Plus it's a little more learning (even trial/error) for you to do.
Lastly
In the getters for your AppSettings static properties you could also do a null or string.IsNullOrWhiteSpace check for the _settings' property in question, and call the LoadSettings() method if so.
This would save you having to manually call it in-code elsewhere.
Useful links
XmlSerializer and how to use the Serialize method
All about what you can do with the FileIO.WriteTextAsync
Not an article, but a similar question: UWP C# Read & Write XML File
I really hope this helps, somewhat.
Good luck!
I can't sort this weird issue out and I have tried anything and everything I can think of.
I got 5 pages, everyone of them passing variables with navigation this way:
Pass:
NavigationSerice.Navigate(new Uri("/myPage.xaml?key=" + myVariable, UriKind.Relative));
Retrieve:
If (NavigationContext.QueryString.ContainsKey(myKey))
{
String retrievedVariable = NavigationContext.QueryString["myKey"].toString();
}
I open a list on many pages and one of the pages automatically deletes an item from the list actualProject (actualProject is a variable for a string list). Then, when I go so far back that I reach a specific page - the app throws an exception. Why? I have no idea.
The code that deletes the item:
// Remove the active subject from the availible subjects
unlinkedSubjects.Remove(actualSubject);
unlinkedsubjectsListBox.ItemsSource = null;
unlinkedsubjectsListBox.ItemsSource = unlinkedSubjects;
Then the page that throws the exception's OnNavigatedTo event:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (NavigationContext.QueryString.ContainsKey("key"))
{
actualProject = NavigationContext.QueryString["key"];
try
{
//Read subjectList from IsolatedStorage
subjectList = readSetting(actualProject) != null ? (List<String>)readSetting(actualProject) : new List<String>();
//Put the subjectList into the subjectListBox
subjectListBox.ItemsSource = subjectList;
//Set the subjectsPageTitle to the "actualProject" value, to display the name of the current open project at the top of the screen
subjectsPageTitle.Text = actualProject;
}
catch (Exception)
{
if (language.Equals("en."))
{
// Language is set to english
MessageBox.Show("Couldn't open the project, please try again or please report the error to Accelerated Code - details on the about page");
}
else if (language.Equals("no."))
{
// Language is set to norwegian
MessageBox.Show("Kunne ikke åpne prosjektet, vennligst prøv igjen eller rapporter problemet til Accelerated Code - du finner detaljer på om-siden");
}
}
}
}
Exception:
_exception {System.ArgumentException: Value does not fall within the expected range.} System.Exception {System.ArgumentException}
My theory:
The app kind of loads the currently opened and modified List. Is that possible? No idea.
So there are a number of ways to pass data between pages.
The way you have chosen is the least suggested.
You can use the PhoneApplicationService.Current dictionary but this is messy also if you have a ton of variables, doesn't persist after app shut down and could be simplified.
I wrote a free DLL that kept this exact scenario in mind called EZ_iso.
You can find it here
Basically what you would do to use it is this.
[DataContractAttribute]
public class YourPageVars{
[DataMember]
public Boolean Value1 = false;
[DataMember]
public String Value2 = "And so on";
[DataMember]
public List<String> MultipleValues;
}
Once you have your class setup you can pass it easily between pages
YourPageVars vars = new YourPageVars { /*Set all your values*/ };
//Now we save it
EZ_iso.IsolatedStorageAccess.SaveFile("PageVars",vars);
That's it! Now you can navigate and retrieve the file.
YourPageVars vars = (YourPageVars)EZ_iso.IsolatedStorageAccess.GetFile("PageVars",typeof(YorPageVars));
This is nice because you can use it for more than navigation. You can use it for anything that would require Isolated storage. This data is serialized to the device now so even if the app shuts down it will remain. You can of course always delete the file if you choose as well.
Please make sure to refer to the documentation for any exceptions you have. If you still need help feel free to hit me up on twitter #Anth0nyRussell or amr#AnthonyRussell.info
I'm making a rather "simple" piece of software and at the moment I'm working with one table in my database and reading from the database works and now I was trying to implement inserting into the database, which seems to work as long as the program is running, but when I stop the program (stop debugging in VS) and launch it again, the rows don't seem to be in the database (already checked the .mdf database itself for the rows but they can't be found).
This is the piece of code:
public void saveKlant(klant nieuweKlant)
{
KlantGegevens newKlant = new KlantGegevens();
newKlant.klantNaam = nieuweKlant.naam;
newKlant.klantStraat = nieuweKlant.straat;
newKlant.klantPostcode = nieuweKlant.postcode;
newKlant.klantHuisNummer = nieuweKlant.huisnummer;
newKlant.klantGSM = nieuweKlant.gsm;
newKlant.klantTel = nieuweKlant.telnummer;
newKlant.klantGebDatum = nieuweKlant.gebDatum;
newKlant.klantEmail = nieuweKlant.email;
using (kapsalonEntities context = new kapsalonEntities())
{
try
{
context.KlantGegevens.AddObject(newKlant);
int test = context.SaveChanges();
}
catch
{
throw new InvalidOperationException("het object kon niet toegevoegd worden");
}
}
}
"test" equals 1 (so context.SaveCHanges() = 1) when running the program.
what would be the reason for the data to not be added persistently? since I do use a Context.SaveChanges()?
Thanks in advance.
It looks like you didn't check of the property where the database each time copies himself toi the debug directory. That's why you always get your default data again. Set the property to "if newer"