I am trying to use an ArrayList to store a variable number of strings, and would like to know how to save the ArrayList and its elements so that my windows form can recall their value between program load and exit.
I used to store the information in a text file, but would like to avoid external files if possible.
Thank you for any help you could provide.
You can save the ArrayList (if not ArrayList their are other equivalent classes) using Properties.Settings best part is it allows you the setting variable at Application and user level
A very good example can be found here how to use Settigns http://www.codeproject.com/Articles/17659/How-To-Use-the-Settings-Class-in-C
I've always done using (In Winforms in your case from the sounds of it), the Form_Closing to store to a Properties.Settings variable you'd create beforehand. If it's an ArrayList, you could store it to XML or a comma separated list. Your serizliation/deserialization method will depend on your data.
Have a look at isolated storage.
I used to store the information in a text file, but would like to avoid external files if possible.
Inevitably storing data between runs will require something outside the program's executables.
The registry would work, but the registry is not great for storing anything more than a small amount of information. A database could be used by that adds files.
For text strings a text file – one string per line1 – can be saved and loaded in a single statement. Putting the file into isolated storage or under a dedicated folder in %AppData% limits the chances of a user messing it up.2.
// Load
var theStrings = new ArrayList();
var path = GetSavePath();
if (File.Exists(path)) {
theStrings.AddRange(File.ReadLines(path);
}
// Save:
File.WriteAllLines(GetSavePath(), theStrings.ToArray());
Here using ToArray() as ArrayList doesn't implement IEnumerable<String> (List<String> would be a better choice for a collection and avoid this).
1 This assumes end of line is not valid inside the strings. If this needs to be supported there are a number of options. Some file format to separate the strings by another mechanism, or perhaps the easiest will be to escape characters with a simple transform (eg. \ → \\, newline → \n, and carriage return → \r).
2 You cannot prevent this without significant additional complexity that would use something like a service to load/save as a different user thus allowing the data to be protected by an ACL.
Related
aight so I'm making a WPF application and it has a loading window and on that loading window i want the text to be random every time the app is started any idea on how to do this?
Depending on what you mean by "Random" there could be multiple ways to do this:
Have a Hardcoded list of Loading texts in Application (or a resource like xml or database). Read a random line from this store.
Do a WebApi call to fetch the loading text (You need to create/find relevant WebApi).
Want Truly Random/runtine generated text? Ok - generate a random number in range: −2,147,483,648 to 2,147,483,647. Convert this to UTF-32. Keep appending more chars and/or spaces until a minimum string length is achieved. Use this as the Loading text.
If you are looking for generating a random Integer - Look at this
I have openFileDialog and saveFileDialog with filter (only .dvbcfg extention):
SaveFileDialog saveFileDialog = new SaveFileDialog();
saveFileDialog.Filter = "DVB Configuration File (*.dvbcfg)|*.dvbcfg";
saveFileDialog.DefaultExt = "dvbcfg";
saveFileDialog.AddExtension = true;
It works properly, but when I'm trying to type filename manually it shows files with any extentions w/o filtering and opens/saves them (first - open file, second - save file):
ScreenShot
How to show only files that matches saveFileDialog.Filter?
P.S. I have overwrite function in saveFileDialog.
UPD I have another option - throw an exception when user selected wrong filetype, but I have no idea how to get only file extention from saveFileDialog.FileName string.
At a certain point, you have to "trust" your users. You can steer them towards good ways of working with your program, but at a certain point, you have to recognise that you've put enough simple barriers in their way to prevent accidental misuse1 but you're unlikely to be able to create enough barriers (in these dialogs) to prevent malicious misuse.
The problem is that using wrong file may cause damage to expensive equipment (DVB-3030 Digital Modulator in this case) even if I'm using try/catch to get variables from files (they need to be integers, in try segment I have Convert.ToInteger32) and variable ranges in if/else checks (for example Frequency range should be 10MHz - 90 MHz with 100Hz step). Since program will be used by students, they can purposely try to break it.
And nothing in your current question (or sought answer) would prevent someone from renaming any arbitrary file to have a .dvbcfg extension.
At this point, you "trust" that the user has given you the filename they wish to use. What you need to do next is to validate the contents of the file. If it has a .dvbcfg extension but isn't actually a valid DVB config file, you need to reject it. If it doesn't have a .dvbcfg extension (hey, maybe they're working with an old file system that only allows 8.3 file names :-)) but turns out to have valid content, why be churlish and reject that file?
I would recommend more than just wrapping ToInteger32 calls in try/catch. Go through the file. Ensure it contains exactly what it should and nothing else. Read each parameter value and probably use TryParse on those. Because your code now "expects" to receive invalid inputs. Then validate ranges, etc.
1Which I'd say you've already got.
I need to save the last 10 paths (strings) of files found in a directory. What would be the best way to easily save and retrieve them?
I was thinking about reading and writing to a txt file but I was wondering if there was an easier more efficient way to do that in WPF.
You can use a Serializer to write the array to any kind of file: Json, xml, binary, anything. Then, when you need to load the array, you just Deserialize the file and you have your array variable again.
See this article on how serialization works for more information: https://learn.microsoft.com/en-us/dotnet/standard/serialization/
you can use settings to save your data.
do double click on settings and choose the type -> Browse -> system -> System.Collection.Specialized -> StringCollection .
and choose Scope as User.
just note that first time to use this collection you should create instance of it with new key word.
I know it is not easier. but i am sure it is cleaner.
to do this, first add this namespace:
using MyWpfApplication.Properties;
then use it in this way:
if (Settings.Default.MyStringCollection== null)
{
Settings.Default.MyStringCollection= new System.Collections.Specialized.StringCollection();
Settings.Default.MyStringCollection.Add("string1");
Settings.Default.MyStringCollection.Add("string2");
Settings.Default.Save();
}
else
{
var result = Settings.Default.MyStringCollection;
}
You can use a Configuration fileConfiguration file.
ConfigurationManager Class
I don't think it will support array. You would need path01 - path10.
If you want more of a List then use XML.
I need guidance, someone to point me in the right direction. As the tittle says, I need to save information to a file: Date, string, integer and an array of integers. And I also need to be able to access that information later, when an user wants to review it.
Optional: File is plain text and I can directly check it and it is understandable.
Bonus points if chosen method can be "easily" converted to working with a database in the future instead of individual files.
I'm pretty new to C# and what I've found so far is that I should turn the array into a string with separators.
So, what'd you guys suggest?
// JSON.Net
string json = JsonConvert.SerializeObject(objOrArray);
File.WriteAllText(path, json);
// (note: can also use File.Create etc if don't need the string in memory)
or...
using(var file = File.Create(path)) { // protobuf-net
Serializer.Serialize(file, objOrArray);
}
The first is readable; the second will be smaller. Both will cope fine with "Date, string, integer and an array of integers", or an array of such objects. Protobuf-net would require adding some attributes to help it, but really simple.
As for working with a database as columns... the array of integers is the glitch there, because most databases don't support "array of integers" as a column type. I'd say "separation of concerns" - have a separate model for DB persistence. If you are using the database purely to store documents, then: pretty much every DB will support CLOB and BLOB data, so either is usable. Many databases now have inbuilt JSON support (helper methods, etc), which might make JSON as a CLOB more tempting.
I would probably serialize this to json and save it somewhere. Json.Net is a very popular way.
The advantage of this is also creating a class that can be later used to work with an Object-Relational Mapper.
var userInfo = new UserInfoModel();
// write the data (overwrites)
using (var stream = new StreamWriter(#"path/to/your/file.json", append: false))
{
stream.Write(JsonConvert.SerializeObject(userInfo));
}
//read the data
using (var stream = new StreamReader(#"path/to/your/file.json"))
{
userInfo = JsonConvert.DeserializeObject<UserInfoModel>(stream.ReadToEnd());
}
public class UserInfoModel
{
public DateTime Date { get; set; }
// etc.
}
for the Plaintext File you're right.
Use 1 Line for each Entry:
Date
string
Integer
Array of Integer
If you read the File in your code you can easily seperate them by reading line to line.
Make a string with a specific Seperator out of the Array:
[1,2,3] -> "1,2,3"
When you read the line you can Split the String by "," and gets a Array of Strings. Parse each Entry to int into an Array of Int with the same length.
How to read and write the File get a look at Easiest way to read from and write to files
If you really wants the switch to a database at a point, try a JSON Format for your File. It is easy to handle and there are some good Plugins to work with.
Mfg
Henne
The way I got started with C# is via the game Space Engineers from the Steam Platform, the Mods need to save a file Locally (%AppData%\Local\Temp\SpaceEngineers\ or %AppData%\Roaming\SpaceEngineers\Storage\) for various settings, and their logging is similar to what #H. Sandberg mentioned (line by line, perhaps a separator to parse with later), the upside to this is that it's easy to retrieve, easy to append, easy to overwrite, and I'm pretty sure it's even possible to retrieve File Size, which when combined with File Deletion and File Creation can prevent runaway File Sizes as this allows you to set an Upper Limit to check against, allowing you to run it on a Server with minimal impact (probably best to include a minimum Date filter {make sure X is at least Y days old before deleting it for being over Z Bytes} to prevent Debugging Data Loss {"Why was it over that limit?"})
As far as the actual Code behind the idea, I'm approximately at the same Skill Level as the OP, which is to say; Rookie, but I would advise looking at the Coding in the Space Engineers Mods for some Samples (plus it's not half bad for a Beta Game), as they are almost all written in C#. Also, the Programmable Blocks compile in C# as well, so you'll be able to use that to both assist in learning C# and reinforce and utilize what you already know (although certain C# commands aren't allowed for security reasons, utilizing the Mod API you'll have more flexibility to do things such as Creating/Maintaining Log Files, Retrieving/Modifying Object Properties, etc.), You are even capable of printing Text to various in Game Text Monitors.
I apologise if my Syntax needs some work, and I'm sorry I am not currently capable of just whipping up some Code to solve your issue, but I do know
using System;
Console.WriteLine("Hello World");
so at least it's not a total loss, but my example Code likely won't compile, since it's likely missing things like: an Output Location, perhaps an API reference or two, and probably a few other settings. Like I said, I'm New, but that is a valid C# Command, I know I got that part correct.
Edit: here's a better attempt:
using System;
class Test
{
static void Main()
{
string a = "Hello Hal, ";
string b = "Please open the Airlock Doors.";
string c = "I'm sorry Dave, "
string d = "I'm afraid I can't do that."
Console.WriteLine(a + b);
Console.WriteLine(c + d);
Console.Read();
}
}
This:
"Hello Hal, Please open the Airlock Doors."
"I'm sorry Dave, I'm afraid I can't do that."
Should be the result. (the "Quotation Marks" shouldn't appear in the readout {the last Code Block}, that's simply to improve readability)
I have a noteapp, two pages:
MainPage.xaml — the creation of notes;
NoteList.xaml — a list of notes.
Notes are saved by means of IsolatedStorage, and appear in NoteList.xaml (listbox), but notes with the same name is not stored, how to fix it?
I need to be able to add notes with the same name (but with different content).
Thanks!
Are you using the note name as the file name? If so... don't do that. Save each file with a unique name. There are myriad ways of doing this. You could use a GUID or a timestamp, or you could append a timestamp to the end of the file name. If you were so inclined you could store all of the notes in a single formatted file-- perhaps XML.
What you need is a way to uniquely identify each note without using:
a. The note's name
b. The note's contents
While using a timestamp might make sense for your application right now (since a user probably cannot create two disparate notes simultaneously), using a timestamp to identify each note could lead to problems down the line if you wanted to implement say... a server side component to your application. What happens if in version 23 of your application (which obviously sells millions in the first months), you decide to allow users to collaborate on notes, and a Note is shared between two instances of your app where they happened to be created at the EXACT same time? You'd have problems.
A reasonable solution to finding a unique identifier for each Note in your application is through the use of the Guid.NewGuid method. You should do this when the user decides to "save" the note (or if your app saves the note the moment it's created, or at some set interval to allow for instant "drafts".
Now that we've sufficiently determined a method of uniquely identifying each Note that your application will allow a user to create, we need to think about how that data should be stored.
A great way to do this is through the use of XmlSerializer, or better yet using the third party library Json.Net. But for the sake of simplicity, I recommend doing something a bit easier.
A simpler method (using good ole' plain text) would be the following:
1: {Note.Name}
2: {Guid.ToString()}
3: {Note.Contents}
4: {Some delimiter}
When you are reading the file from IsolatedStorage, you would read through the file line by line, considering each "chunk" of lines between the start of the file and each {Some delimiter} and the end of the file to be the data for one "Note".
Keep in mind there are some restrictions with this format. Mainly, you have to keep the user from having the last part of their note's contents be equal to the {Some delimiter} (which you are free to arbitrarily define btw). To this end, it may be helpful to use a string of characters the user is not likely to enter, such as "##&&ENDOFNOTE&&##" Regardless of how unlikely it is the user will type that in, you need to check to make sure before you save to IsolatedStorage that the end of the Note does not contain this string, because it will break your file format.
If you want a simple solution that works, use the above method. If you want a good solution that's scalable, use JSON or XML and figure out a file format that makes sense to you. I highly encourage you to look into JSON, it's value reaches so much further than this isolated scenario.
I've had a need to write notes to IsolatedStorage. What I did was to them them to a file.IsolatedStorageFile I write date on which the note was written and then note. From the list box i store them to two arrays. Then before exiting the app, write them to a file.
try
{
using (IsolatedStorageFile storagefile = IsolatedStorageFile.GetUserStoreForApplication())
{
if (storagefile.FileExists("NotesFile"))
{
using (IsolatedStorageFileStream fileStream = storagefile.OpenFile("NotesFile", FileMode.Open, FileAccess.ReadWrite))
{
StreamWriter writer = new StreamWriter(fileStream);
for (int i = 0; i < m_noteCount; i++)
{
//writer.Write(m_arrNoteDate[i].ToShortDateString());
writer.Write(m_arrNoteDate[i].ToString("d", CultureInfo.InvariantCulture));
writer.Write(" ");
writer.Write(m_arrNoteString[i]);
writer.WriteLine("~`");
}
writer.Close();
}
}