I have a form with 30 text boxes which contain default setting I set in my code. the user has an option to change it , but I want to know how can I save the new values chosen by the user in one (or more) of those text boxes for next time I run the application.
thanks a lot
If you don't care about editing your saved file and don't intend to rename the textboxes or change the layout of them you can leave the ordering of values to the compiler. Use this for saving:
// first collect all values
List<string> allvalues = this.Controls.OfType<TextBox>().Select(x => x.Text).ToList();
// write to file
System.IO.File.WriteAllText("yourPath", String.Join(Environment.NewLine, allvalues));
and this for loading:
//load the values:
string [] alllines = System.IO.File.ReadAllLines("yourPath");
List<TextBox> allTextboxes = this.Controls.OfType<TextBox>().ToList();
for (int i = 0; i < allTextboxes.Count; i++)
{
allTextboxes[i].Text = alllines[i];
}
Explanation:
this.Controls.OfType<TextBox>() gets you all controls that are textboxes in your windows form.
String.Join(Environment.NewLine, allvalues) combines all values to a string separated by a newline.
the app.config is an XML file with many predefined configuration sections available and support for custom configuration sections. An example where we have a tag for setting Name mySetting and mySetting2 is shown
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="mySetting" value="myValue1"/>
<add key="mySetting2" value="myValue12" />
</appSettings>
</configuration>
In order to use config files you must add a reference to System.Configuration, so you can use ConfigurationManager class. Below is a sample for reading and writing to app.config file:
WRITE TO CONFIG From TEXTBOX:
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
config.AppSettings.Settings["mySetting"].Value=textBox1.Text;
config.Save();
READ from Config:
var mySetting = ConfigurationManager.AppSettings["mySetting"];
Simple way to solve this problem:
//To write textbox values to file (may be used on form close)
using (System.IO.StreamWriter sw = new StreamWriter("values.txt"))
{
foreach (var control in this.Controls)
{
if (control is TextBox)
{
TextBox txt = (TextBox)control;
sw.WriteLine(txt.Name + ":" + txt.Text);
}
}
}
//To read textbox values from file (may be used on form load)
using (System.IO.StreamReader sr = new StreamReader("values.txt"))
{
string line = "";
while((line=sr.ReadLine()) != null)
{
//Ugly, but work in every case
string control = line.Substring(0, line.IndexOf(':') );
string val = line.Substring(line.IndexOf(':') + 1);
if(this.Controls[control] != null)
{
((TextBox)this.Controls[control]).Text = val;
}
}
}
Save values in file. For 30 text field you can use 30 lines or just comma separated values.
When user change the value then write new values in that file, so on next startup you will have new values in file and each time don't have to read old data.
Related
What my goal with my piece of code is not to save duplicate domains to a .txt file if a checkbox is ticked.
Code:
// save to file here
if (footprints.Any(externalUrl.Contains))
{
// Load all URLs into an array ...
var hash = new List<string>(File.ReadAllLines(#"Links\" + lblFootprintsUsed.Text));
// Find the domain root url e.g. site.com ...
var root = Helpers.GetRootUrl(externalUrl);
if (chkBoxDoNotSaveDuplicateDomains.Checked == true)
{
if (!hash.Contains(Helpers.GetRootUrl(externalUrl)))
{
using (var sr = new StreamWriter(#"Links\" + lblFootprintsUsed.Text, true))
{
// before saving make & to & and get rid of #038; altogether ...
var newURL = externalUrl.Replace("&", "&").Replace("#038;", " ");
sr.WriteLine(newURL);
footprintsCount++;
}
}
}
if (chkBoxDoNotSaveDuplicateDomains.Checked == false)
{
if (!hash.Contains(externalUrl))
{
using (var sr = new StreamWriter(#"Links\" + lblFootprintsUsed.Text, true))
{
// before saving make & to & and get rid of #038; altogether ...
var newURL = externalUrl.Replace("&", "&").Replace("#038;", " ");
sr.WriteLine(newURL);
footprintsCount++;
}
}
}
}
The code above starts off by checking if a certain footprint pattern is found in a URL structure, if it does we load all URLs into a List the way !hash.Contains(externalUrl) should work is NOT to add duplicate URLs to the .txt file, but i can see from testing it does add complete duplicate URLs (the first issue) i never noticed this before, then i tried to add !hash.Contains(Helpers.GetRootUrl(externalUrl)) which should not add duplicate domains to the .txt file.
So unchecked, the code should not add duplicate URLs to file.
And checked the code should not add duplicate domains to file.
Both seem to fail, i cannot see any issue in the code as such, is there anyhting i am missing or could do better? any help is appreciated.
Here you are adding the full URL to the file, but while checking you are comparing only with the root URL
Modify the condition
if (!hash.Contains(Helpers.GetRootUrl(externalUrl)))
to
if (!hash.Any(x => x.Contains(Helpers.GetRootUrl(externalUrl))))
I'm using C# Code in Ranorex 5.4.2 to create a CSV file, have data gathered from an XML file and then have it write this into the CSV file. I've managed to get this process to work but I'm experiencing an issue where there are 12 blank lines created beneath the gathered data.
I have a file called CreateCSVFile which creates the CSV file and adds the headers in, the code looks like this:
writer.WriteLine("PolicyNumber,Surname,Postcode,HouseNumber,StreetName,CityName,CountyName,VehicleRegistrationPlate,VehicleMake,VehicleModel,VehicleType,DateRegistered,ABICode");
writer.WriteLine("");
writer.Flush();
writer.Close();
The next one to run is MineDataFromOutputXML. The program I am automating provides insurance quotes and an output xml file is created containing the clients details. I've set up a mining process which has a variable declared at the top which shows as:
string _PolicyHolderSurname = "";
[TestVariable("3E92E370-F960-477B-853A-0F61BEA62B7B")]
public string PolicyHolderSurname
{
get { return _PolicyHolderSurname; }
set { _PolicyHolderSurname = value; }
}
and then there is another section of code which gathers the information from the XML file:
var QuotePolicyHolderSurname = (XmlElement)xmlDoc.SelectSingleNode("//cipSurname");
string QuotePolicyHolderSurnameAsString = QuotePolicyHolderSurname.InnerText.ToString();
PolicyHolderSurname = QuotePolicyHolderSurnameAsString;
Report.Info( "Policy Holder Surname As String = " + QuotePolicyHolderSurnameAsString);
Report.Info( "Quote Policy Holder Surname = " + QuotePolicyHolderSurname.InnerText);
The final file is called SetDataSource and it puts the information into the CSV file, there is a variable declared at the top like this:
string _PolicyHolderSurname = "";
[TestVariable("222D47D2-6F66-4F05-BDAF-7D3B9D335647")]
public string PolicyHolderSurname
{
get { return _PolicyHolderSurname; }
set { _PolicyHolderSurname = value; }
}
This is then the code that adds it into the CSV file:
string Surname = PolicyHolderSurname;
Report.Info("Surname = " + Surname);
dataConn.Rows.Add(new string[] { Surname });
dataConn.Store();
There are multiple items in the Mine and SetDataSource files and the output looks like this in Notepad++:
Picture showing the CSV file after the code has been run
I believe the problem lies in the CreateCSVFile and the writer.WriteLine function. I have commented this region out but it then produces the CSV with just the headers showing.
I've asked some of the developers I work with but most don't know C# very well and no one has been able to solve this issue yet. If it makes a difference this is on Windows Server 2012r2.
Any questions about this please ask, I can provide the whole files if needed, they're just quite long and repetitive.
Thanks
Ben Jardine
I had the exact same thing to do in Ranorex. Since the question is a bit old I didn't checked your code but here is what I did and is working. I found an example (probably on stack) creating a csv file in C#, so here is my adaptation for using in Ranorex UserCodeCollection:
[UserCodeCollection]
public class UserCodeCollectionDemo
{
[UserCodeMethod]
public static void ConvertXmlToCsv()
{
System.IO.File.Delete("E:\\Ranorex_test.csv");
XDocument doc = XDocument.Load("E:\\lang.xml");
string csvOut = string.Empty;
StringBuilder sColumnString = new StringBuilder(50000);
StringBuilder sDataString = new StringBuilder(50000);
foreach (XElement node in doc.Descendants(GetServerLanguage()))
{
foreach (XElement categoryNode in node.Elements())
{
foreach (XElement innerNode in categoryNode.Elements())
{
//"{0}," give you the output in Comma seperated format.
string sNodePath = categoryNode.Name + "_" + innerNode.Name;
sColumnString.AppendFormat("{0},", sNodePath);
sDataString.AppendFormat("{0},", innerNode.Value);
}
}
}
if ((sColumnString.Length > 1) && (sDataString.Length > 1))
{
sColumnString.Remove(sColumnString.Length-1, 1);
sDataString.Remove(sDataString.Length-1, 1);
}
string[] lines = { sColumnString.ToString(), sDataString.ToString() };
System.IO.File.WriteAllLines(#"E:\Ranorex_test.csv", lines);
}
}
For your information, a simple version of my xml looks like that:
<LANGUAGE>
<ENGLISH ID="1033">
<TEXT>
<IDS_TEXT_CANCEL>Cancel</IDS_TEXT_CANCEL>
<IDS_TEXT_WARNING>Warning</IDS_TEXT_WARNING>
</TEXT>
<LOGINCLASS>
<IDS_LOGC_DLGTITLE>Log In</IDS_LOGC_DLGTITLE>
</LOGINCLASS>
</ENGLISH>
<FRENCH ID="1036">
<TEXT>
<IDS_TEXT_CANCEL>Annuler</IDS_TEXT_CANCEL>
<IDS_TEXT_WARNING>Attention</IDS_TEXT_WARNING>
</TEXT>
<LOGINCLASS>
<IDS_LOGC_DLGTITLE>Connexion</IDS_LOGC_DLGTITLE>
</LOGINCLASS>
</FRENCH>
</LANGUAGE>
I've got a saved filed called records.txt on the phone. A line of it looks like this:
XY Family, 2015.11.10. 12:12 2
Name of family, date, time and another number.
Now, when the user opens the app, I'd like to check this file, and if there's a date there, that is already passed, then delete that line from the text file.
My logic was, first copy the lines to an array of string, then check each one if the date is passed, and if not, copy those into a new array of string. Delete the text file and create a new one with the 2nd string array.
The funny thing is, my code works with windows forms, but fails on android. Here it is:
var path = global::Android.OS.Environment.ExternalStorageDirectory.AbsolutePath;
var records = Path.Combine(path.ToString(), "records.txt");
string[] recordLines; // original lines
string[] newLines; // new lines, excluding the obsolete date lines
int counter = 0;
if (System.IO.File.Exists(records))
{
try
{
recordLines = System.IO.File.ReadAllLines(records);
newLines = new string[recordLines.Length];
foreach(string rl in recordLines)
{
Regex mypattern = new Regex(#"Család, ([ ._0-9A-Za-z-]+) \w");
string recordDate = mypattern.Match(rl).Groups[1].Value;
DateTime dt = Convert.ToDateTime(recordDate);
if (!((dt - DateTime.Today).TotalSeconds < 0))
{
newLines[counter] = rl;
counter++;
}
}
File.Delete(records);
using (StreamWriter sw = new StreamWriter(records))
{
foreach(string s in newLines)
{
sw.WriteLine(s);
}
}
}
catch (Exception)
{
// tba
}
}
EDIT: It fails by not even touching the text file. I tried to create a new one, but it won't do that either. I assume that means something is wrong with the arrays.
I have set two permissions:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
EDIT2: Apparently my phone wrapped the line of the file, therefore making the regex unusable. I'm fixing it right now.
EDIT3: It was indeed the phone's saving problem, it wrapped the text unusable.
I have a Xml file with values for the dropdown.I want to provide the path in Web.config and bind the values to drop down from web.config.
Firstly to read the location from web.config use System.Configuration class, something like the following should work
string filePath = ConfigurationManager.AppSettings["FilePath"];
to access a file on the server use Server.MapPath e.g.
Server.MapPath(filepath);
to bind an xml file to the dropdown you could use the following, there are easier ways but this will allow for any other manipulation you need to do
1: Get the list of items
public static List<string> GetFamiliesList()
{
List<string> families = new List<string>();
try
{
using (StreamReader streamreader = new StreamReader(Server.MapPath(filepath)))
{
XElement xe = XElement.Load(streamreader);
foreach (XElement children in xe.Elements("Family"))
{
families.Add(children.Attribute("Name").Value);
}
}
}
catch
{
}
return families;
}
2: bind to dropdown
dropdownList.DataSource = GetFamiliesList();
I've written a small utility that allows me to change a simple AppSetting for another application's App.config file, and then save the changes:
//save a backup copy first.
var cfg = ConfigurationManager.OpenExeConfiguration(pathToExeFile);
cfg.SaveAs(cfg.FilePath + "." + DateTime.Now.ToFileTime() + ".bak");
//reopen the original config again and update it.
cfg = ConfigurationManager.OpenExeConfiguration(pathToExeFile);
var setting = cfg.AppSettings.Settings[keyName];
setting.Value = newValue;
//save the changed configuration.
cfg.Save(ConfigurationSaveMode.Full);
This works well, except for one side effect. The newly saved .config file loses all the original XML comments, but only within the AppSettings area. Is it possible to to retain XML comments from the original configuration file AppSettings area?
Here's a pastebin of the full source if you'd like to quickly compile and run it.
I jumped into Reflector.Net and looked at the decompiled source for this class. The short answer is no, it will not retain the comments. The way Microsoft wrote the class is to generate an XML document from the properties on the configuration class. Since the comments don't show up in the configuration class, they don't make it back into the XML.
And what makes this worse is that Microsoft sealed all of these classes so you can't derive a new class and insert your own implementation. Your only option is to move the comments outside of the AppSettings section or use XmlDocument or XDocument classes to parse the config files instead.
Sorry. This is an edge case that Microsoft just didn't plan for.
Here is a sample function that you could use to save the comments. It allows you to edit one key/value pair at a time. I've also added some stuff to format the file nicely based on the way I commonly use the files (You could easily remove that if you want). I hope this might help someone else in the future.
public static bool setConfigValue(Configuration config, string key, string val, out string errorMsg) {
try {
errorMsg = null;
string filename = config.FilePath;
//Load the config file as an XDocument
XDocument document = XDocument.Load(filename, LoadOptions.PreserveWhitespace);
if(document.Root == null) {
errorMsg = "Document was null for XDocument load.";
return false;
}
XElement appSettings = document.Root.Element("appSettings");
if(appSettings == null) {
appSettings = new XElement("appSettings");
document.Root.Add(appSettings);
}
XElement appSetting = appSettings.Elements("add").FirstOrDefault(x => x.Attribute("key").Value == key);
if (appSetting == null) {
//Create the new appSetting
appSettings.Add(new XElement("add", new XAttribute("key", key), new XAttribute("value", val)));
}
else {
//Update the current appSetting
appSetting.Attribute("value").Value = val;
}
//Format the appSetting section
XNode lastElement = null;
foreach(var elm in appSettings.DescendantNodes()) {
if(elm.NodeType == System.Xml.XmlNodeType.Text) {
if(lastElement?.NodeType == System.Xml.XmlNodeType.Element && elm.NextNode?.NodeType == System.Xml.XmlNodeType.Comment) {
//Any time the last node was an element and the next is a comment add two new lines.
((XText)elm).Value = "\n\n\t\t";
}
else {
((XText)elm).Value = "\n\t\t";
}
}
lastElement = elm;
}
//Make sure the end tag for appSettings is on a new line.
var lastNode = appSettings.DescendantNodes().Last();
if (lastNode.NodeType == System.Xml.XmlNodeType.Text) {
((XText)lastNode).Value = "\n\t";
}
else {
appSettings.Add(new XText("\n\t"));
}
//Save the changes to the config file.
document.Save(filename, SaveOptions.DisableFormatting);
return true;
}
catch (Exception ex) {
errorMsg = "There was an exception while trying to update the config value for '" + key + "' with value '" + val + "' : " + ex.ToString();
return false;
}
}
If comments are critical, it might just be that your only option is to read & save the file manually (via XmlDocument or the new Linq-related API). If however those comments are not critical, I would either let them go or maybe consider embedding them as (albeit redundant) data elements.