I need to save and load a listview / observablecollection when I open and close the app.
I have search around here and other places, and tried some things, but nothing seems to work.
I've pasted the code I found, that I thought did the trick. maybe it does with some changes.
//This one is for adding items, and it works fine.
try
{
Tanknings.Add(new Tankning { Date = Dato.Date.ToString("dd-MM-yyyy"),
KmTaeller = KmTaeller.Text,
LiterTanket = Math.Round(Convert.ToDouble(LiterTanket.Text), 2).ToString(),
Pris = Math.Round(Convert.ToDouble(Pris.Text), 2).ToString(),
KmKoert = (Convert.ToInt32(KmTaeller.Text) - Convert.ToInt32(AktuelKmTaeller.Text)).ToString(),
PrisPrLiter = Math.Round((Convert.ToDouble(Pris.Text) / Convert.ToDouble(LiterTanket.Text)), 2).ToString(),
KmPrLiter = Math.Round(((Convert.ToDouble(KmTaeller.Text) - (Convert.ToDouble(AktuelKmTaeller.Text))) / Convert.ToDouble(LiterTanket.Text)), 2).ToString() });
}
catch
{
}
//This i what i tried to save and load the items.
private async void saveTankninger()
{
XmlSerializer xs = new XmlSerializer(typeof(ObservableCollection<Tankning>));
using (StreamWriter wr = new StreamWriter("Files/Tankninger.xml"))
{
xs.Serialize(wr, Tanknings);
}
/* Firstly we will use StorageFolder class from the Windows.Storage namespace
to get path to the LocalFolder for our application: */
StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
/* Then we need to have reference to the file where we can store notes:
Note that if file exists we do not want to create another one: */
StorageFile notesFile = await storageFolder.CreateFileAsync("Tankninger.txt", CreationCollisionOption.OpenIfExists);
// Now we want to serialize list with the notes to save it in the JSON format ine the file:
var serializedNotesList = JsonConvert.SerializeObject(Tanknings);
// Last step is to write serialized list with notes to the text file:
await FileIO.WriteTextAsync(notesFile, serializedNotesList);
}
private async void loadTankninger()
{
/* Firstly we will use StorageFolder class from the Windows.Storage namespace
to get path to the LocalFolder for our application: */
StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
/* Then we need to have reference to the file where we can store notes:
Note that if file exists we do not want to create another one: */
StorageFile notesFile = await storageFolder.CreateFileAsync("Tankninger.txt", CreationCollisionOption.OpenIfExists);
// Read serialized notes list from the file:
string serializedNotesList = await FileIO.ReadTextAsync(notesFile);
// Deserialize JSON list to the ObservableCollection:
if (serializedNotesList != null)
{
Tanknings = JsonConvert.DeserializeObject<ObservableCollection<Tankning>>(serializedNotesList);
tankningTable.ItemsSource = Tanknings;
}
}
Assuming that you are using newtonsoft JSON library and have populated List
Serialise :
using Newtonsoft.Json;
List<Class_name> aList = getListFromSomehwere();
string json = JsonConvert.SerializeObject(aList);
// Do whatever you want with string, e.g. save to file
Deserialise :
using Newtonsoft.Json;
string json = ReadFile(); // Your function to read all text from file
List<Class_name> aList = (JsonConvert.DeserializeObject<IEnumerable<Class_name>>(json)).ToList();
// Do whatever you want with this list
To save on close - just add event to your application closing event, serialise list and save it to file.
To open on load - add window_loaded event (or form shown or whatever you prefer), read all file, deserialise json. There's many ways to approach this and it is up to you to decide what you want to do.
Edit : JSON.NET DeserializeObject to List of Objects might help
Related
I'm trying to save my text file in UWP, but It always saving to different file. By the way I'm using MVVM architecture.
My Code
FileSavePicker savePicker = new FileSavePicker();
savePicker.SuggestedFileName = "New Text Document";
savePicker.SuggestedStartLocation = PickerLocationId.Desktop;
savePicker.FileTypeChoices.Add("Text Document", new List<string>() { ".txt" });
savePicker.DefaultFileExtension = ".txt";
StorageFile storageFile = await savePicker.PickSaveFileAsync();
if(storageFile != null)
{
CachedFileManager.DeferUpdates(storageFile);
await FileIO.WriteTextAsync(storageFile, Document.Text);
FileUpdateStatus updateStatus = await CachedFileManager.CompleteUpdatesAsync(storageFile);
Document.FileName = savePicker.SuggestedFileName;
Document.IsSaved = true;
}
My code is always saving texts on different file. I'm trying to save my text to same file.
In UWP there is a feature called FutureAccessList. It can be used to save the token of the file, opened with the FilePicker. When you now want to save it again you can retrive the StorageFile by the token and write to it.
Add a FileToken property to your Document class:
public string FileToken { get; set; }
Now when you pick your file you add the file to the FutureAccessList:
...
StorageFile storageFile = await savePicker.PickSaveFileAsync();
if (storageFile != null)
{
CachedFileManager.DeferUpdates(storageFile);
await FileIO.WriteTextAsync(storageFile, Document.Text);
FileUpdateStatus updateStatus = await CachedFileManager.CompleteUpdatesAsync(storageFile);
Document.FileName = savePicker.SuggestedFileName;
Document.IsSaved = true;
//Add the file to the FutureAccessList to get it back later
Document.FileToken = StorageApplicationPermissions.FutureAccessList.Add(storageFile);
}
To retrive the file and save it again:
public async void SaveFile()
{
//Get the file back from the FutureAccessList by its token and write to it
StorageFile file = await StorageApplicationPermissions.FutureAccessList.GetFileAsync(Document.FileToken);
await FileIO.WriteTextAsync(file, Document.Text);
}
Now when you e.g. save your Document class to Json and retrive it after the app restarts you can still use the FileToken to write to the file. There is no need to let the user pick it again using the SaveFilePicker.
When the code above is to complicated or there is no need for this (I don't know what you need this for), you can put a StorageFile propertie directly to your Document class and put the file, that the SaveFilePicker returned in it. But this won't work when restarting the app. The user would always have to pick the file again.
I want to write my current state of a game into a JSON file so that once the user comes back they can either resume or start new. I'm creating a hello world to take user input, store it in JSON and load it back in.
I currently can load JsonObject very quickly using this method
public JObject GetJsonData(string jsonFileName, string dirNameJsonLivesIn)
{
if (string.IsNullOrEmpty(jsonFileName))
throw new ArgumentNullException(jsonFileName);
var assembly = typeof(MainPage).GetTypeInfo().Assembly;
var defaultPath = $"{assembly.GetName().Name}.{jsonFileName}";
var extendedPath = $"{assembly.GetName().Name}.{dirNameJsonLivesIn}.{jsonFileName}";
if (string.IsNullOrEmpty(dirNameJsonLivesIn))
extendedPath = defaultPath;
Stream stream = assembly.GetManifestResourceStream(extendedPath);
using (var reader = new StreamReader(stream))
{
var jsonString = reader.ReadToEnd();
return JObject.Parse(jsonString);
}
}
With this method, I can access objects with ["strings"] just like python does very easily and painlessly.
Problem accures when I try to write to the file. I get an error Access denied... I have given permission on the manifest for Write_External_Files or something along the line. Still get the same error. I've also done some research and there has been a few line of code which people recommended to add to the MainActivity.cs but that didn't work either.
Using this method to write file
private void StoreData_Clicked(object sender, EventArgs e)
{
var jsonFileName = "Statefile.json";
var text = entryBox.Text;
var state = new Dictionary<string, string>();
var assembly = typeof(MainPage).GetTypeInfo().Assembly;
var defaultPath = $"{assembly.GetName().Name}.{jsonFileName}";
state.Add("CurrentState", text);
var json = JsonConvert.SerializeObject(state, Formatting.Indented);
File.WriteAllText(defaultPath, json);
}
Could someone explain why this is happening? Why do I have the ability to read the external_resources but not write to them? Oh yeah, I have set my properties to Embedded Resource and also Always Copy.
Update - Error
System.UnauthorizedAccessException
Message=Access to the path "/HelloWorldXamarin.Statefile.json" is denied.
I'll explain the problem right away, but first of all...is this achievable?
I have a Document Type in Umbraco where I store data from a Form. I can store everything except the file.
...
content.SetValue("notes", item.Notes);
content.SetValue("curriculum", item.Curriculum); /*this is the file*/
...
I'm adding items like this where SetValue comes from the following namespace namespace Umbraco.Core.Models and this is the function signature void SetValue(string propertyTypeAlias, object value)
And the return error is the following
"String or binary data would be truncated.
↵The statement has been terminated."
Did I missunderstood something? Shouldn't I be sending the base64? I'm adding the image to a media file where it creates a sub-folder with a sequential number. If I try to add an existing folder it appends the file just fine but if I point to a new media sub-folder it also returns an error. Any ideas on how should I approach this?
Thanks in advance
Edit 1: After Cryothic answer I've updated my code with the following
byte[] tempByte = Convert.FromBase64String(item.Curriculum);
var mediaFile = _mediaService.CreateMedia(item.cvExtension, -1, Constants.Conventions.MediaTypes.File);
Stream fileStream = new MemoryStream(tempByte);
var fileName = Path.GetFileNameWithoutExtension(item.cvExtension);
mediaFile.SetValue("umbracoFile", fileName, fileStream);
_mediaService.Save(mediaFile);
and the error happens at mediaFile.SetValue(...).
If I upload a file from umbraco it goes to "http://localhost:3295/media/1679/test.txt" and the next one would go to "http://localhost:3295/media/1680/test.txt". Where do I tell on my request that it has to add to the /media folder and increment? Do I only point to the media folder and umbaco handles the incrementation part?
If I change on SetValue to the following mediaFile.SetValue("curriculum", fileName, fileStream); the request succeeds but the file is not added to the content itself and the file is added to "http://localhost:3295/umbraco/media" instead of "http://localhost:3295/media".
If I try the following - content.SetValue("curriculum", item.cvExtension); - the file is added to the content but with the path "http://localhost:3295/umbraco/test.txt".
I'm not understanding very well how umbraco inserts files into the media folder (outside umbraco) and how you add the media service path to the content service.
Do you need to save base64?
I have done something like that, but using the MediaService.
My project had the option to upload multiple images on mulitple wizard-steps, and I needed to save them all at once. So I looped through the uploaded files (HttpFileCollection) per step. acceptedFiletypes is a string-list with the mimetypes I'd allow.
for (int i = 0; i < files.Count; i++) {
byte[] fileData = null;
UploadedFile uf = null;
try {
if (acceptedFiletypes.Contains(files[i].ContentType)) {
using (var binaryReader = new BinaryReader(files[i].InputStream)) {
fileData = binaryReader.ReadBytes(files[i].ContentLength);
}
if (fileData.Length > 0) {
uf = new UploadedFile {
FileName = files[i].FileName,
FileType = fileType,
FileData = fileData
};
}
}
}
catch { }
if (uf != null) {
projectData.UploadedFiles.Add(uf);
}
}
After the last step, I would loop throug my projectData.UploadedFiles and do the following.
var service = Umbraco.Core.ApplicationContext.Current.Services.MediaService;
var mediaTypeAlias = "Image";
var mediaItem = service.CreateMedia(fileName, parentFolderID, mediaTypeAlias);
Stream fileStream = new MemoryStream(file.FileData);
mediaItem.SetValue("umbracoFile", fileName, fileStream);
service.Save(mediaItem);
I also had a check which would see if the uploaded filename was ending on ".pdf". In that case I'd change the mediaTypeAlias to "File".
I hope this helps.
I am looking for a way to append strings-text to a file in a Windows Store App. I have tried reading the file and then creating a new one to overwrite it but Windows Store Apps C# does not work like C where when creating a new file with the same name overwrites the old one. Currently my code is opening the old file, reading it's contents, deleting it and creating a new one with the content I read plus the content I wish to append.
I know there is a better way but I cannot seem to find it. So How may I append text to an already existent file in a Windows Store App (Windows RT)?
EDIT--
I tried this
var folder = Windows.ApplicationModel.Package.Current.InstalledLocation;
var file = await folder.GetFileAsync("feedlist.txt");
await Windows.Storage.FileIO.AppendTextAsync(file, s);
but I keep getting System.UnauthorizedAccessException
according to MSDN this happens when the file is readonly (I checked with right click properties, it's not) and if I do not have the necessary privileges to access the file
what should I do?
You can use the FileIO class to append to a file. For example ...
// Create a file in local storage
var folder = ApplicationData.Current.LocalFolder;
var file = await folder.CreateFileAsync("temp.txt", CreationCollisionOption.FailIfExists);
// Write some content to the file
await FileIO.WriteTextAsync(file, "some contents");
// Append additional content
await FileIO.AppendTextAsync(file, "some more text");
Check out the File Access Sample for more examples.
Using FileIO.AppendTextAsync is a good option.
Please find the code snippet for this.
First it creates a folder, if not exists. Otherwise it will not create.
Then it creates a file if not exists.
Finally appending the text in the file.
public static async void WriteTrace(TraceEventType eventType, string msg, [CallerMemberName] string methodName = "")
{
const string TEXT_FILE_NAME = "Trace.txt";
string logMessage = eventType.ToString() + "\t" + methodName + "\t" + msg ;
IEnumerable<string> lines = new List<string>() { logMessage };
StorageFolder localFolder = ApplicationData.Current.LocalFolder;
StorageFolder tempFolder = ApplicationData.Current.TemporaryFolder;
//if(localFolder.CreateFolderQuery(Windows.Storage.Search.CommonFolderQuery.)
StorageFolder LogFolder = await localFolder.CreateFolderAsync("LogFiles", CreationCollisionOption.OpenIfExists);
await LogFolder.CreateFileAsync(TEXT_FILE_NAME, CreationCollisionOption.OpenIfExists);
StorageFile logFile = await LogFolder.GetFileAsync(TEXT_FILE_NAME);
await FileIO.AppendLinesAsync(logFile, lines);
}
I am working on a class that creates or opens an xml file:
namespace QTabs
{
public class DataLayer
{
XmlDocument XMLDocObject = new XmlDocument();
StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
StorageFile storageFile;
string xmlFile = "DataStore.xml";
public DataLayer()
{
loadXML();
}
public async void loadXML()
{
//if XML doc doesnt exist create it
try
{
storageFile = await ApplicationData.Current.LocalFolder.GetFileAsync(xmlFile);
}
catch (FileNotFoundException)
{
storageFile = null;
}
if (storageFile == null)
{
storageFile = await storageFolder.CreateFileAsync(xmlFile);
// Manipulate the xml document.
var root = XMLDocObject.CreateElement("SyncTimes");
XMLDocObject.AppendChild(root);
var childTag1 = XMLDocObject.CreateElement("id");
var childTag2 = XMLDocObject.CreateElement("dateTime");
root.AppendChild(childTag1);
root.AppendChild(childTag2);
await XMLDocObject.SaveToFileAsync(storageFile);
}
else
{
storageFile = await storageFolder.GetFileAsync(xmlFile);
}
}
public async void addSyncTime()
{
XmlElement x1 = XMLDocObject.CreateElement("SyncTime");
XmlElement x11 = XMLDocObject.CreateElement("id");
x11.InnerText = "1";
x1.AppendChild(x11);
XmlElement x12 = XMLDocObject.CreateElement("dateTime");
x12.InnerText = DateTime.Now.ToString();
x1.AppendChild(x12);
await XMLDocObject.SaveToFileAsync(storageFile);
}
}
}
My issue is with the above addSyncTime() method. When it runs it results in the XML file being empty, including removing the elements added on creation.
What am I doing wrong?
Hard to say without a good, minimal, complete code example that reliably reproduces the problem. However, your code appears to have two different problems:
When the XML file is already present, you don't ever bother to actually load it, leaving XMLDocObject referencing an empty document. (Indeed, the storageFile != null case seems completely out of place; not only does it not load the XML from storageFile as I'd expect, it actually re-retrieves the storageFile object by calling GetFileAsync() again).
Your addSyncTime() method creates new elements, but never adds them to the XML document tree.
Given the above, I would expect the program behavior to be:
The first time you run the program, the XML document is created.
Any subsequent time you run the program (unless you delete the XML document), attempts to update the XML document will empty the document.
In neither case would I expect new SyncTime elements to be added. The first time you run the program, you'll get the root SyncTimes element and its initial id and dateTime children, but not any SyncTime elements. After that, the XML document will be emptied, and you'll still not get any new SyncTime elements.
If the above does not address your concern, please provide a good code example as described in the link I provide above.