web-dev-qa-db-fra.com

Comment obtenir une collection de valeurs List <string> à partir de app.config dans WPF?

L'exemple suivant remplit le ItemsControl avec une liste de BackupDirectories que je reçois du code.

Comment puis-je changer cela afin d'obtenir les mêmes informations à partir du fichier app.config?

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>

code-behind:

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>
67
Edward Tanguay

Vous pouvez créer votre propre section de configuration personnalisée dans le fichier app.config. Il existe assez de petutorielsenviron pour commencer. En fin de compte, vous pourriez avoir quelque chose comme ça:

<configSections>
    <section name="backupDirectories" type="TestReadMultipler2343.BackupDirectoriesSection, TestReadMultipler2343" />
  </configSections>

<backupDirectories>
   <directory location="C:\test1" />
   <directory location="C:\test2" />
   <directory location="C:\test3" />
</backupDirectories>

Pour compléter la réponse de Richard, voici le C # que vous pouvez utiliser avec son exemple de 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; }
    }
}

Ensuite, vous pouvez accéder à la section de configuration de backupDirectories comme suit:

List<directory> dirs = ConfigurationManager.GetSection("backupDirectories") as List<directory>;
116
Richard Nienaber

Vous pouvez les avoir délimités par des points-virgules dans une seule valeur, par exemple.

App.config

<add key="paths" value="C:\test1;C:\test2;C:\test3" />

C #

var paths = new List<string>(ConfigurationManager.AppSettings["paths"].Split(new char[] { ';' }));
138
Adam Ralph

J'aime la réponse de Richard Nienaber, mais comme l'a souligné Chuu, cela ne dit pas vraiment comment accomplir ce que Richard appelle une solution. C’est pourquoi j’ai choisi de vous expliquer comment j’ai fini par le faire, en terminant avec le résultat dont parle Richard.

La solution

Dans ce cas, je crée un widget de message d'accueil qui doit savoir quelles options il doit accueillir. Il peut s'agir d'une solution trop sophistiquée pour les questions relatives aux PO, car je crée également un conteneur pour de futurs widgets.

J'ai d'abord configuré ma collection pour gérer les différentes salutations

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;
    }
}

Nous créons ensuite l'élément de message d'accueil exact et son interface

(Vous pouvez omettre l'interface, c'est comme ça que je le fais toujours.)

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; }
    }
}

La propriété greetingWidget ainsi notre configuration comprend la collection

Nous définissons notre collection GreetingWidgetCollection comme le ConfigurationPropertygreetingWidget afin de pouvoir utiliser "greetingWidget" comme conteneur dans le XML résultant.

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; }
    }
}

Le XML résultant

<?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>

et vous l'appeleriez comme ça

List<GreetingElement> greetings = Widgets.GreetingWidget.All;
31
Squazz

Il y a en fait une classe très peu connue dans la BCL à cet effet exactement: CommaDelimitedStringCollectionConverter . Cela sert de moyen terme entre avoir un ConfigurationElementCollection (comme dans la réponse de Richard) et analyser la chaîne vous-même (comme dans la réponse d'Adam).

Par exemple, vous pourriez écrire la section de configuration suivante:

public class MySection : ConfigurationSection
{
    [ConfigurationProperty("MyStrings")]
    [TypeConverter(typeof(CommaDelimitedStringCollectionConverter))]
    public CommaDelimitedStringCollection MyStrings
    {
        get { return (CommaDelimitedStringCollection)base["MyStrings"]; }
    }
}

Vous pourriez alors avoir un app.config qui ressemble à ceci:

<?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>

Enfin, votre code ressemblerait à ceci:

var section = (MySection)ConfigurationManager.GetSection("foo");
foreach (var s in section.MyStrings)
    Console.WriteLine(s); //for example
31
Ohad Schneider

Avait le même problème, mais résolu d'une manière différente. Ce n'est peut-être pas la meilleure solution, mais c'est une solution.

dans app.config:

<add key="errorMailFirst" value="[email protected]"/>
<add key="errorMailSeond" value="[email protected]"/>

Ensuite, dans ma classe de wrapper de configuration, j'ajoute une méthode pour rechercher des clés.

        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();
        }

Pour tous ceux qui liront ceci, je conviens que la création de votre propre section de configuration personnalisée est plus propre et plus sécurisée, mais pour les petits projets, où vous avez besoin de quelque chose de rapide, cela pourrait le résoudre.

9
ruffen

Dans App.config:

<add key="YOURKEY" value="a,b,c"/>

En C #:

string[] InFormOfStringArray = ConfigurationManager.AppSettings["YOURKEY"].Split(',').Select(s => s.Trim()).ToArray();
List<string> list = new List<string>(InFormOfStringArray);
5
Divya

Merci pour la question. Mais j'ai trouvé ma propre solution à ce problème. Au début, j'ai créé une méthode

    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;
    }

Ensuite, j'ai utilisé cette méthode pour produire une instance d'une classe

var connStrs = GetSettingsWithDictionary<AuthMongoConnectionStrings>();

J'ai la prochaine déclaration de classe

public class AuthMongoConnectionStrings
{
    public Dictionary<string, string> ConnectionStrings { get; set; }
}

et je stocke mes paramètres dans App.config

<configuration>    
  <AuthMongoConnectionStrings
  First="first"
  Second="second"
  Third="33" />
</configuration> 
0
Larissa Savchekoo