How to get a List<string> collection of values from app.config in WPF?
下面的示例用我从代码中获得的backupdirectory列表填充itemscontrol。
如何更改此设置,以便从app.config文件中获取相同的信息?
XAML:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | <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> |
代码落后:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | 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:
1 2 3 4 5 6 7 8 9 10 11 12 | <?xml version="1.0" encoding="utf-8" ?> <configuration> <!-- </add>--> </appSettings> </configuration> |
可以将它们用分号分隔为单个值,例如
App.CONFIG
1 |
C.*
您可以在app.config文件中创建自己的自定义配置节。有很多教程可以让你开始学习。最终,您可能会得到这样的结果:
1 2 3 4 5 6 7 8 9 | <configSections> <section name="backupDirectories" type="TestReadMultipler2343.BackupDirectoriesSection, TestReadMultipler2343" /> </configSections> <backupDirectories> <directory location="C:\test1" /> <directory location="C:\test2" /> <directory location="C:\test3" /> </backupDirectories> |
为了补充Richard的答案,这是您可以在他的示例配置中使用的C:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 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; } } } |
然后可以访问backupdirectories配置部分,如下所示:
1 | List<directory> dirs = ConfigurationManager.GetSection("backupDirectories") as List<directory>; |
我喜欢理查德·尼纳伯的回答,但正如邱指出的那样,这并不能说明如何完成理查德所说的解决方案。因此,我选择了提供给你我最后这样做的方式,以理查德所说的结果结束。
解决方案在本例中,我创建了一个问候语小部件,需要知道它必须问候哪些选项。这可能是一个过度工程化的解决方案,因为我也在为未来可能的小部件创建一个容器。
首先,我建立了我的收集处理不同的问候
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | 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; } } |
然后我们创建Acutal问候元素和它的接口
(您可以省略接口,这正是我一直在做的方式。)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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; } } } |
使配置了解集合的GreetingWidget属性
我们将集合
1 2 3 4 5 6 7 8 9 10 11 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 | <?xml version="1.0" encoding="utf-8" ?> <configuration> <widgets> <greetingWidget> ... </greetingWidget> </widgets> </configuration> |
你可以这样称呼它
1 | List<GreetingElement> greetings = Widgets.GreetingWidget.All; |
实际上,在BCL中有一个非常鲜为人知的类用于此目的:commadelimitedStringCollectionConverter。它是一个中间地带,介于拥有一个
例如,您可以编写以下配置部分:
1 2 3 4 5 6 7 8 9 | public class MySection : ConfigurationSection { [ConfigurationProperty("MyStrings")] [TypeConverter(typeof(CommaDelimitedStringCollectionConverter))] public CommaDelimitedStringCollection MyStrings { get { return (CommaDelimitedStringCollection)base["MyStrings"]; } } } |
然后您可以有一个app.config,如下所示:
1 2 3 4 5 6 7 | <?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> |
最后,您的代码如下所示:
1 2 3 | var section = (MySection)ConfigurationManager.GetSection("foo"); foreach (var s in section.MyStrings) Console.WriteLine(s); //for example |
有同样的问题,但用不同的方法解决了它。它可能不是最好的解决方案,但却是一个解决方案。
在App.CONFIG中:
1 |
然后在我的配置包装类中,我添加了一个方法来搜索键。
1 2 3 4 5 6 7 8 | 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(); } |
对于任何阅读本文的人,我都同意创建您自己的自定义配置节是更干净、更安全的,但是对于小项目,如果您需要快速的东西,这可能会解决它。
在App.config:
1 |
C中:
1 2 | string[] InFormOfStringArray = ConfigurationManager.AppSettings["YOURKEY"].Split(',').Select(s => s.Trim()).ToArray(); List<string> list = new List<string>(InFormOfStringArray); |