I wrote this to quickly test
Why arent my settings being saved? The first time i run this i have 3(old)/3(current) elements. The second time i get 3(old)/5(current), third time 5(old)/5(current).
When i close the app the settings completely disappear. Its 3 again when i run it. I made no changes to the app. Why arent my settings being saved
private void button2_Click(object sender, EventArgs e)
{
MyApp.Properties.Settings.Default.Reload();
var saveDataold = MyApp.Properties.Settings.Default.Context;
var saveData = MyApp.Properties.Settings.Default.Context;
saveData["user"] = textBox1.Text;
saveData["pass"] = textBox2.Text;
MyApp.Properties.Settings.Default.Save();
}
You should be using the exposed properties instead of putting your data in the context:
var saveData = MyApp.Properties.Settings.Default;
saveData.user = textBox1.Text;
saveData.pass = textBox2.Text;
The context
provides contextual information that
the provider can use when persisting
settings
and is in my understanding not used to store the actual setting values.
Update: if you don't want to use the Settings editor in Visual Studio to generate the strong-typed properties you can code it yourself. The code generated by VS have a structure like this:
[UserScopedSetting]
[DebuggerNonUserCode]
[DefaultSettingValue("")]
public string SettingName
{
get { return ((string)(this["SettingName"])); }
set { this["SettingName"] = value; }
}
You can easily add more properties by editing the Settings.Designer.cs file.
If you don't want to use the strong-typed properties you can use the this[name] indexer directly. Then your example will look like this:
var saveData = MyApp.Properties.Settings.Default;
saveData["user"] = textBox1.Text;
saveData["pass"] = textBox2.Text;
Related
To make this easier, I will show my code and then explain what im trying to do.
CODE+EXPLANATION:
First, when the user clicks on a button it goes to Other with additonal information.
private void button1_Click(object sender, EventArgs e)
=> Other("https://pastebin.com/raw/something", "Program1", "A");
private void button2_Click(object sender, EventArgs e)
=> Other("https://pastebin.com/raw/something", "Program2", "B");
Second, I download an XML document and extract neccesary information from it:
private void Other(string UniversalURL, string ProductNAME, string ProductCHANNEL)
{
//Download the Doc
XmlDocument document = new XmlDocument();
document.Load(UniversalURL);
string expandedEnvString = Environment.ExpandEnvironmentVariables("%USERPROFILE%/AppData/Local/Temp/zADU.xml");
File.WriteAllText(expandedEnvString, document.InnerXml);
XmlDocument doc = new XmlDocument();
doc.Load(expandedEnvString);
//Get the needed Nodes
XmlNode nodeXMLProgram = doc.DocumentElement.SelectSingleNode($"/{ProductNAME}");
string XMLProgram = nodeXMLProgram.InnerText;
// Creation of Button Here
}
GOAL: What I want to be able to do is use the strings, extracted from the XML and use them as variables in the creation of button, Kind of like this:
Button Program(XMLProgram) = new Button();
Program(XMLProgram).Height = 22;
Program(XMLProgram).Width = 122;
Program(XMLProgram).BackColor = Color.FromArgb(230, 230, 230);
Program(XMLProgram).ForeColor = Color.Black;
Program(XMLProgram).Name = "DynamicButton";
Program(XMLProgram).Click += new EventHandler(ProgramProgram(XMLProgram)_Click);
Program(XMLProgram).BringToFront();
Controls.Add(ProgramProgram(XMLProgram));
Would I be able to do this? Help would be appreciated! Sorry for confusing title, I don't know how to phrase it properly.
You can use Reflection to look for and set the properties of the object you are deserializing automatically, provided you have a properly formatted XML file.
Read your XML file through XDocument or XmlDocument, extract from it the type of control you need to create (button, textbox, etc), also extract the property names to set from the XML, and the values to set them to. Then create an instance of said control type, and use code like this to go through your property list from the XML and set them in your instance:
// New instance of the control (read the type from the XML and create accordingly)
var ctrlInstance = new Button();
// Get a reference to the type of the control created.
var ctrlType = ctrlInstance.GetType();
// Dictionary to contain property names and values to set (read from XML)
var properties = new Dictionary<string, object>();
foreach (var xmlProp in properties)
{
// Get a reference to the actual property in the type
var prop = ctrlType.GetProperty(xmlProp.Key);
if (prop != null && prop.CanWrite)
{
// If the property is writable set its value on the instance you created
// Note that you have to make sure the value is of the correct type
prop.SetValue(ctrlInstance, xmlProp.Value, null);
}
}
If you intend to create an entire program this way, including code, you will have to use Roslyn to compile your code at runtime, which can be somewhat complicated to put into practice. In that case, you don't need an XML file, you just need to put put all your code into a source file and compile it, then instantiate it in your own program. If you just want to create a form programmatically and handle events in its parent form, this will work fine.
I've got a bit of an issue where the Word.ParagraphFormat properties are not working. Here is my code:
private void ThisDocument_Startup(object sender, EventArgs e)
{
Word.ParagraphFormat format = new Word.ParagraphFormat();
format.Alignment = Word.WdParagraphAlignment.wdAlignParagraphLeft;
// text is as if it were center alignment; behaves like ".wdAlighnParagraphCenter"
format.OutlineLevel = Word.WdOutlineLevel.wdOutlineLevelBodyText;
// text boundaries around every section after line return rather than the entire page text and header/footer; behaves like ".wdOutlineLevelX" (X for 1-9)
Word.Style stl = Styles[Word.WdBuiltinStyle.wdStyleNormalTable] as Word.Style;
stl.UnhideWhenUsed = true;
stl.ParagraphFormat = paragraphFormat;
stl.NoSpaceBetweenParagraphsOfSameStyle = true;
}
Is there something I need to add or take away? Is there something else that needs to be set or assigned? Or, is there something over writing it later?
The Office object models work differently than the .NET object models - the technology is over twenty years old and the way people thought was different. In the Office object models you need to first create the object. Only then can you define its properties. (As opposed to that, in the .NET world you can define properties, then create the object and assign the properties.)
So for defining a Style you go about it more like this:
private void ThisDocument_Startup(object sender, EventArgs e)
{
Word.Style Stl = Styles[Word.WdBuiltinStyle.wdStyleHeading1] as Word.Style;
Stl.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphLeft;
Stl.ParagraphFormat.OutlineLevel = Word.WdOutlineLevel.wdOutlineLevelBodyText;
Stl.UnhideWhenUsed = true;
Stl.NoSpaceBetweenParagraphsOfSameStyle = true;
}
Also please note that you can't set the above properties for a Table style, as in your question's sample code. These settings are only appropriate for paragraph (or linked - although I strongly advise against using linked) styles.
I have a simple list, like this:
fruitList = new FruitList();
Apple fruit1 = new Apple("red", "small");
Banana fruit2 = new Banana("yellow", "big");
fruitList.AddFruit(fruit1);
fruitList.AddFruit(fruit2);
My program displays this in a Textbox:
textbox.Text = fruitList.DescribeCurrentFruit()
+
public string DescribeCurrentFruit()
{
string description;
if (fruitStock.Count > 0)
{
description = fruitStock[fruitCurrentlyDisplayed].Description();
}
else
{
description = "No Fruits in stock";
}
return description;
}
Currently, the List's two current objects/items (fruit1, fruit2) are automatically loaded as they are a part of my Window Form's load_event. However, if they're not a part of the load_event, or if I want to add more items/objects to the list at runtime, then permanently save them, how can I do so?
Well, I can do so by saving items in the project's property settings. (Serialization is an alternative option, but far too complex for me, and I want the simplest solution.) How do I go about this? Is there any sample code? I understand I first need to add items into my properties, but struggle even at this step.
So, I have Form called Preferences with TabControl in it. This TabControl contains several TabPages(General, Advanced, Misc, ...) with few comboboxes, checkboxes and labels. Each of this control inside TabPage is assigned Application Settings Property Binding (aka they show saved user settings, user can change them etc...).
I know that there is a method to reset all settings (Properties.Settings.Default.Reset();), but is there a way how to reset only settings inside one TabPage?
My solution is to iterate thru controls in TabPage, check if it is combobox, label etc and then reset it´s value to default, but is there a "oneliner" solution to this ?
Use the following solution to get the original value of a single setting:
(The example assumes you want to get the ORIGINAL value of a setting named 'Username')
var defaultUsername = Properties.Settings.Default.GetType()
.GetProperty(nameof(Properties.Settings.Default.Username))
.GetCustomAttribute<System.Configuration.DefaultSettingValueAttribute>()
.Value;
Important - this solution will always return a string value. make sure to parse it properly, or use this extension method I wrote:
public static T GetDefaultValue<T>(this ApplicationSettingsBase settings, string settingKey)
{
return (T)Convert.ChangeType(settings.GetType()
.GetProperty(settingsKey)
.GetCustomAttribute<DefaultSettingValueAttribute>()
.Value, typeof(T));
}
Usage:
var defaultNumber = Properties.Settings.Default.GetDefaultValue<int>(nameof(Properties.Settings.Default.Number));
The ApplicationSettings doesn't have built-in support to reset just some properties. But to solve the problem, you can use either of these options:
Create a method which resets all bound controls of a TabPage
Using Multiple Settings Files with Designer Support
Option 1 - Create a method which resets all bound controls of a TabPage
You can create a method which look at controls of the tab page and check if it's bound to application settings, find the property in settings and reset its value to the default value. Then you can reset settings of a TebPage width one line of code: ResetSettings(tabPage1);.
Here is the method:
private void ResetSettings(TabPage tabPage)
{
foreach (Control c in tabPage.Controls)
{
foreach (Binding b in c.DataBindings)
{
if (b.DataSource is ApplicationSettingsBase)
{
var settings = (ApplicationSettingsBase)b.DataSource;
var key = b.BindingMemberInfo.BindingField;
var property = settings.Properties[key];
var defaultValue = property.DefaultValue;
var type = property.PropertyType;
var value = TypeDescriptor.GetConverter(type).ConvertFrom(defaultValue);
settings[key] = value;
//You can also save settings
settings.Save();
}
}
}
}
Option 2 - Using Multiple Settings Files with Designer Support
If the reason of using a single settings file is because of designer support, you should know you can have designer support also with multiple settings files. Then you can use different settings files and reset each settings group separately. You can simply encapsulate them in a single class using such code:
public static class MySettings
{
public static Sample.General General
{
get { return Sample.General.Default; }
}
public static Sample.Advanced Advanced
{
get { return Sample.Advanced.Default; }
}
public static void ResetAll()
{
General.Reset();
Advanced.Reset();
}
public static void SaveAll()
{
General.Save();
Advanced.Save();
}
}
To reset a setting group it's enough to call MySettings.General.Reset();
To reset all settings, you can call MySettings.ResetAll();
Note for design-time support
To have designer support for binding properties to settings, create multiple settings files in root of your project. Don't put settings files in folders. The setting picker, only shows Settings.settings file which is in Properties folder and those files which are in root of project. This way you can see different settings files and settings properties in a tree-view like this:
TabPage page = aTabControl.SelectedTab;
var controls = page.Controls;
foreach (var control in controls)
{
//do stuff
}
Try this:
private void button2_Click(object sender, EventArgs e)
{
TabPage page = tabControl1.SelectedTab;
var controls = page.Controls;
foreach (var control in controls)
{
if(control is TextBox)
{
//do stuff
}
if(control is ComboBox )
{
ComboBox comboBox = (ComboBox)control;
if (comboBox.Items.Count > 0)
comboBox.SelectedIndex = 0;
comboBox.Text = string.Empty;
}
}
}
I have created two settings file under properties in c#. Basically I have to apply settings based on a particular set of condition
for example the settings file are "myset1" and "myset2"
both these settings have similar structure
myset1
price = 100
qty = 100
myset2
price = 150
qty = 20
in my application, if value of variable "appColor" is "blue" myset1 has to be used if variable "appColor" is "red" myset2 has to be used.
in my code
productPrice.Text = //based on the "appColor" selection value from myset1 or myset2 has to be displayed.
I tried this but not working
Settings setSelector = new Settings();
if(appColor == "blue")
{
setSelector = myset1.Default;
}
else(appColor == "red")
{
setSelector = myset2.Default;
}
I am getting error that "cannot convert source type "myset1" to settings"
EDIT: my aim is that productPrice.Text = setSelector.Price; remains same even when settings are changed so I don't have to change code here and just have to change the settings. basically full forms gets filled based on the settings selected.
any help would be appreciated
I tried below code. it worked correctly.
I have two Textboxes, in which i am setting Price and Qty based on color.
Object obj = new Object();
if(appColor == "blue")
{
obj = (System.Configuration.SettingsPropertyCollection)Properties.Settings.Default.Properties;
}
else(appColor == "red")
{
obj = (System.Configuration.SettingsPropertyCollection)Properties.Settings1.Default.Properties;
}
foreach (System.Configuration.SettingsProperty p in Properties.Settings.Default.Properties)
{
if (p.Name=="Qty")
textBox1.Text = p.DefaultValue.ToString();
else if (p.Name=="Price")
textBox2.Text = p.DefaultValue.ToString();
}
I Hope this helps :)
After playing around with it a bit and referencing this MSDN article specifically the last section on adding alternate sets of settings.
To Add an Additional Set of Settings
From the Project menu, choose Add New Item. The Add New Item dialog box opens.
In the Add New Item dialog box, select Settings File.
In the Name box, give the settings file a name, such as SpecialSettings.settings, and click Add to add the file to your
solution.
In Solution Explorer, drag the new settings file into the Properties folder. This allows your new settings to be available in
code.
Add and use settings in this file as you would any other settings file. You can access this group of settings through the
Properties.SpecialSettings object.
I then realized that each settings file is its own separate class therefore you have to go back to a common class. By doing so you will loose your individual properties and have to cast it to the proper class. I then looked at this SO question searching for dynamic casting. According to JaredPar's answer it appears that the easiest way to do this would be to use the dynamic keyword and let the class type be figured out at runtime.
i.e.
Class level Declaration:
dynamic setSelector;
Intializing it during Form Load:
private void Form1_Load(object sender, EventArgs e)
{
if(appColor == "blue")
{
setSelector = Properties.myset1.Default;
}
else if(appColor == "red")
{
setSelector = Properties.myset2.Default;
}
textBox1.Text = setSelector.qty.ToString();
}