How to get list of <string> collection of values from app.config in WPF?
The following example populates the ItemsControl list of BackupDirectories that I get from the code.
How can I change this to get the same information from the app.config file?
XAML:
<Window x:Class="TestReadMultipler2343.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="300"> <Grid Margin="10"> <Grid.RowDefinitions> <RowDefinition Height="30"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="120"/> <ColumnDefinition Width="160"/> </Grid.ColumnDefinitions> <TextBlock Grid.Row="0" Grid.Column="0" Text="Title:"/> <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Title}"/> <TextBlock Grid.Row="1" Grid.Column="0" Text="Backup Directories:"/> <ItemsControl Grid.Row="1" Grid.Column="1" ItemsSource="{Binding BackupDirectories}"/> </Grid> </Window> background code:
using System.Collections.Generic; using System.Windows; using System.Configuration; using System.ComponentModel; namespace TestReadMultipler2343 { public partial class Window1 : Window, INotifyPropertyChanged { #region ViewModelProperty: Title private string _title; public string Title { get { return _title; } set { _title = value; OnPropertyChanged("Title"); } } #endregion #region ViewModelProperty: BackupDirectories private List<string> _backupDirectories = new List<string>(); public List<string> BackupDirectories { get { return _backupDirectories; } set { _backupDirectories = value; OnPropertyChanged("BackupDirectories"); } } #endregion public Window1() { InitializeComponent(); DataContext = this; Title = ConfigurationManager.AppSettings.Get("title"); GetBackupDirectoriesInternal(); } void GetBackupDirectoriesInternal() { BackupDirectories.Add(@"C:\test1"); BackupDirectories.Add(@"C:\test2"); BackupDirectories.Add(@"C:\test3"); BackupDirectories.Add(@"C:\test4"); } void GetBackupDirectoriesFromConfig() { //BackupDirectories = ConfigurationManager.AppSettings.GetValues("backupDirectories"); } #region INotifiedProperty Block public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); } } #endregion } } app.config:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <appSettings> <add key="title" value="Backup Tool" /> <!--<add key="backupDirectories"> <add value="C:\test1"/> <add value="C:\test2"/> <add value="C:\test3"/> <add value="C:\test4"/> </add>--> </appSettings> </configuration> You can create your own configuration section in the app.config file. There are quite a few tutorials around to get you started. Ultimately, you might have something like this:
<configSections> <section name="backupDirectories" type="TestReadMultipler2343.BackupDirectoriesSection, TestReadMultipler2343" /> </configSections> <backupDirectories> <directory location="C:\test1" /> <directory location="C:\test2" /> <directory location="C:\test3" /> </backupDirectories> To complement Richard's answer, this is C #, which you can use with its exemplary configuration:
using System.Collections.Generic; using System.Configuration; using System.Xml; namespace TestReadMultipler2343 { public class BackupDirectoriesSection : IConfigurationSectionHandler { public object Create(object parent, object configContext, XmlNode section) { List<directory> myConfigObject = new List<directory>(); foreach (XmlNode childNode in section.ChildNodes) { foreach (XmlAttribute attrib in childNode.Attributes) { myConfigObject.Add(new directory() { location = attrib.Value }); } } return myConfigObject; } } public class directory { public string location { get; set; } } } You can then access the backupDirectories configuration section as follows:
List<directory> dirs = ConfigurationManager.GetSection("backupDirectories") as List<directory>; You could split them with two commas by one value, for example
App.config
<add key="paths" value="C:\test1;C:\test2;C:\test3" /> FROM#
var paths = new List<string>(ConfigurationManager.AppSettings["paths"].Split(new char[] { ';' })); Actually for this purpose there is actually a very little-known class in BCL: CommaDelimitedStringCollectionConverter . It serves as an intermediate link between what has a ConfigurationElementCollection (as in Richard's answer) and independently parses the string (as in Adam's answer).
For example, you can write the following configuration section:
public class MySection : ConfigurationSection { [ConfigurationProperty("MyStrings")] [TypeConverter(typeof(CommaDelimitedStringCollectionConverter))] public CommaDelimitedStringCollection MyStrings { get { return (CommaDelimitedStringCollection)base["MyStrings"]; } } } You can have app.config that looks like this:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="foo" type="ConsoleApplication1.MySection, ConsoleApplication1"/> </configSections> <foo MyStrings="a,b,c,hello,world"/> </configuration> Finally, your code will look like this:
var section = (MySection)ConfigurationManager.GetSection("foo"); foreach (var s in section.MyStrings) Console.WriteLine(s); //for example I adore Richard Nienaber, but, as Chuu remarked, he really does not say how to accomplish what Richard mentions as a solution. So I decided to give you how I did it, ending with the result Richard is talking about.
Decision
In this case, I create a welcome widget that needs to know what options it needs to welcome. This may be an over-solution to the OPs question, as I am also creating a container for possible future widgets.
First I set up my collection to handle different greetings
public class GreetingWidgetCollection : System.Configuration.ConfigurationElementCollection { public List<IGreeting> All { get { return this.Cast<IGreeting>().ToList(); } } public GreetingElement this[int index] { get { return base.BaseGet(index) as GreetingElement; } set { if (base.BaseGet(index) != null) { base.BaseRemoveAt(index); } this.BaseAdd(index, value); } } protected override ConfigurationElement CreateNewElement() { return new GreetingElement(); } protected override object GetElementKey(ConfigurationElement element) { return ((GreetingElement)element).Greeting; } } Then we create the acutal greeting element and its interface
(You can omit the interface, that's exactly how I always do it.)
public interface IGreeting { string Greeting { get; set; } } public class GreetingElement : System.Configuration.ConfigurationElement, IGreeting { [ConfigurationProperty("greeting", IsRequired = true)] public string Greeting { get { return (string)this["greeting"]; } set { this["greeting"] = value; } } } The greetingWidget property, so our configuration understands the collection
We define our GreetingWidgetCollection collection as ConfigurationProperty greetingWidget so that we can use "greetingWidget" as our container in the resulting XML.
public class Widgets : System.Configuration.ConfigurationSection { public static Widgets Widget => ConfigurationManager.GetSection("widgets") as Widgets; [ConfigurationProperty("greetingWidget", IsRequired = true)] public GreetingWidgetCollection GreetingWidget { get { return (GreetingWidgetCollection) this["greetingWidget"]; } set { this["greetingWidget"] = value; } } } XML received
<?xml version="1.0" encoding="utf-8" ?> <configuration> <widgets> <greetingWidget> <add greeting="Hej" /> <add greeting="Goddag" /> <add greeting="Hello" /> ... <add greeting="Konnichiwa" /> <add greeting="Namaskaar" /> </greetingWidget> </widgets> </configuration> And you would call it like this
List<GreetingElement> greetings = Widgets.GreetingWidget.All; Had the same problem but solved it differently. This may not be the best solution, but a solution.
in app.config:
<add key="errorMailFirst" value="test@test.no"/> <add key="errorMailSeond" value="krister@tets.no"/> Then, in my shell wrapper class, I add a key lookup method.
public List<string> SearchKeys(string searchTerm) { var keys = ConfigurationManager.AppSettings.Keys; return keys.Cast<object>() .Where(key => key.ToString().ToLower() .Contains(searchTerm.ToLower())) .Select(key => ConfigurationManager.AppSettings.Get(key.ToString())).ToList(); } For everyone who reads this, I agree that creating your own configuration section is cleaner and safer, but for small projects where you need something quick, this can solve the problem.
In App.config:
<add key="YOURKEY" value="a,b,c"/> In C #:
string[] InFormOfStringArray = ConfigurationManager.AppSettings["YOURKEY"].Split(',').Select(s => s.Trim()).ToArray(); List<string> list = new List<string>(InFormOfStringArray); Thanks for the question. But I found my solution to this problem. First I created a method
public T GetSettingsWithDictionary<T>() where T:new() { IConfigurationRoot _configurationRoot = new ConfigurationBuilder() .AddXmlFile($"{Assembly.GetExecutingAssembly().Location}.config", false, true).Build(); var instance = new T(); foreach (var property in typeof(T).GetProperties()) { if (property.PropertyType == typeof(Dictionary<string, string>)) { property.SetValue(instance, _configurationRoot.GetSection(typeof(T).Name).Get<Dictionary<string, string>>()); break; } } return instance; } Then I used this method to instantiate the class
var connStrs = GetSettingsWithDictionary<AuthMongoConnectionStrings>(); I have the following class declaration
public class AuthMongoConnectionStrings { public Dictionary<string, string> ConnectionStrings { get; set; } } and I save my settings in App.config
<configuration> <AuthMongoConnectionStrings First="first" Second="second" Third="33" /> </configuration>