Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.76/33: Рейтинг темы: голосов - 33, средняя оценка - 4.76
124 / 106 / 7
Регистрация: 14.02.2010
Сообщений: 263

Хранение настроек приложения в директории программы

12.03.2012, 08:44. Показов 6306. Ответов 16
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
А как сделать, чтобы настройки хранились только в папке программы, а не чёрте где?
 Комментарий модератора 
Одна тема - один вопрос (Правила п.3.15)
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
12.03.2012, 08:44
Ответы с готовыми решениями:

Хранение настроек программы
Всем Привет! Вопрос, где лучше хранить настройки программы. 1)В БД не надо, так как для каждой новой программы создавать новую...

Хранение настроек программы в файле
Поставлена такая задача: создать некий редактор картинок. Т.е. пользователь добавляет п-количество картинок и/или подписей к ним (с...

Хранение настроек программы, варианты
Привет, каким образом вы храните настройки программы? 1)Ну стандартный Setting - бред, ибо перемещаем программу и настройки слетают. ...

16
 Аватар для nio
6050 / 3460 / 336
Регистрация: 14.06.2009
Сообщений: 8,136
Записей в блоге: 2
12.03.2012, 10:29
serg42, можно создать свой класс, который будет сохранять настройки в xml-файл в указанном месте
0
 Аватар для taras atavin
4226 / 1796 / 211
Регистрация: 24.11.2009
Сообщений: 27,562
12.03.2012, 10:37
Цитата Сообщение от serg42 Посмотреть сообщение
А как сделать, чтобы настройки хранились только в папке программы, а не чёрте где?
А как они у тебя оказались чёрт знает где?
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
12.03.2012, 10:43
taras atavin, в .NET есть готовый класс для хранения настроек приложения, по дефолту он сохраняет файл с настройками в /user/AppData/[Manufacturer]/[Product]/[Version]/user.config.
1
 Аватар для nio
6050 / 3460 / 336
Регистрация: 14.06.2009
Сообщений: 8,136
Записей в блоге: 2
12.03.2012, 11:33
kolorotur, вот это похоже ТС и не устраивает. Как-то изменить этот дефолт можно?
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
12.03.2012, 11:37
Лучший ответ Сообщение было отмечено как решение

Решение

nio, можно, но только реализовав свой SettingsProvider, унаследовав его от одноименного класса.
Потом свою реализацию можно прицепить файлу настроек через атрибут [SettingsProvider(typeof(MySettingsProvid er))]
4
 Аватар для taras atavin
4226 / 1796 / 211
Регистрация: 24.11.2009
Сообщений: 27,562
12.03.2012, 11:49
А зачем вообще нужен этот сеттингспровайде? Кто мешает просто скинуть данные в файл?
0
Эксперт Java
 Аватар для turbanoff
4094 / 3828 / 745
Регистрация: 18.05.2010
Сообщений: 9,331
Записей в блоге: 12
12.03.2012, 12:00
Цитата Сообщение от kolorotur Посмотреть сообщение
nio, можно, но только реализовав свой SettingsProvider, унаследовав его от одноименного класса.
Потом свою реализацию можно прицепить файлу настроек через атрибут [SettingsProvider(typeof(MySettingsProvid er))]
Вот в этой теме я выкладывал реализацию провайдера, найденного на просторах интернета и немного допиленную.
Цитата Сообщение от taras atavin
А зачем вообще нужен этот сеттингспровайде? Кто мешает просто скинуть данные в файл?
По нескольким причинам.
Во-первых, чтобы не изобретать велосипед, а пользоваться уже готовым решением, на что уйдет меньше времени.
Во-вторых, у "своей" реализации наверняка будет проблемы при многопоточном доступе, или при запуске нескольких экземпляров.
2
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
12.03.2012, 12:04
taras atavin, ну как вам сказать... Зачем на плюсах нужна STL? Что мешает свой вектор реализовать?
То же самое и тут: платформой предлагаются готовые классы, которые можно использовать в своих целях. Ну а делать это или нет - выбор программиста. Хочется возиться с файлами - бога ради, можно и самому в файл скидывать.

Ну а провайдер - это лишь еще один уровень абстракции: можно изменить провайдер, который будет хранить данные не в файле, а, скажем, в базе, при этом не меняя абсолютно никакой другой код, где используются настройки. Можно и свои классы писать, но зачем, если есть готовый каркас для архитектуры?
0
 Аватар для taras atavin
4226 / 1796 / 211
Регистрация: 24.11.2009
Сообщений: 27,562
12.03.2012, 12:05
Готовое учитывает, какие именно настройки тебе нужны? Не верю. А чтоб его допилить, времени уйдёт не меньше, а больше, так как надо всё делать с ноля и при этом ещё тратить время на то, чтоб разобраться с недорешением.
0
Эксперт .NET
 Аватар для kolorotur
17823 / 12973 / 3382
Регистрация: 17.09.2011
Сообщений: 21,261
12.03.2012, 12:09
Цитата Сообщение от taras atavin Посмотреть сообщение
Готовое учитывает, какие именно настройки тебе нужны?
Разумеется.

Цитата Сообщение от taras atavin Посмотреть сообщение
Не верю.
По вопросам веры - это в церковь.
1
Эксперт Java
 Аватар для turbanoff
4094 / 3828 / 745
Регистрация: 18.05.2010
Сообщений: 9,331
Записей в блоге: 12
12.03.2012, 12:20
SettingsProvider довольно логичная штука. Настройки это же не нечто "такое что знаю только я", а представляют собой обычные .net объекты, которые можно сериализовать. Вот он их и сериализует за вас.
0
124 / 106 / 7
Регистрация: 14.02.2010
Сообщений: 263
12.03.2012, 12:48  [ТС]
Во блин, Вы тут размазали Вопрос-то пустяковый, я даж и тему-то создавать не стал.
Если кому интересно сделал следующим нехитрым образом:

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
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
public sealed class MySettings : ConfigurationSection
{
    #region Default
    private static MySettings _default = null;
    public static bool InitDefault()
    {
               
        if (_default == null)
        {
            MySettings sets = null;
            try
            {
                Configuration config = ConfigurationManager.OpenExeConfiguration(Application.ExecutablePath);
                if (config.Sections["MySettings"] == null)
                {
                    sets = new MySettings();
                    config.Sections.Add("MySettings", sets);
                    config.Save(ConfigurationSaveMode.Minimal, true);
                }
                else sets = (MySettings)config.Sections["MySettings"];
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message, "Ошибка получения настроек", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }
            _default = sets;
        }
        return true;
    }
    public static MySettings Default
    {
        get
        {
            if (_default == null) InitDefault();
            return _default;
        }
    }
    #endregion
 
    public MySettings()
    {
        base.Properties.Add(new ConfigurationProperty("db_server", typeof(string), "localhost"));
        base.Properties.Add(new ConfigurationProperty("db_user", typeof(string), "root"));
        base.Properties.Add(new ConfigurationProperty("db_pass", typeof(string), "pass"));
        base.Properties.Add(new ConfigurationProperty("db_name", typeof(string), "test2"));
    }
 
    public void Save()
    {
        this.CurrentConfiguration.Save(ConfigurationSaveMode.Modified);
    }
 
    public string DBServer
    {
        get
        {
            return (string)this["db_server"];
        }
        set
        {
            this["db_server"] = value;
        }
    }
 
    public string DBUser
    {
        get
        {
            return (string)this["db_user"];
        }
        set
        {
            this["db_user"] = value;
        }
    }
 
    public string DBPassword
    {
        get
        {
            return (string)this["db_pass"];
        }
        set
        {
            this["db_pass"] = value;
        }
    }
 
    public string DBName
    {
        get
        {
            return (string)this["db_name"];
        }
        set
        {
            this["db_name"] = value;
        }
    }
}
1
0 / 0 / 0
Регистрация: 21.09.2016
Сообщений: 1
15.11.2016, 12:20
serg42, добрый день. Класс твой заинтересовал. Я тоже озадачен сохранением настроек. Подскажи пожалуйста как им корректно пользоваться.
Что происходит у меня: да собственно ничего почему то не происходит. Я пробовал протестировать код так:
Code
1
2
3
4
5
MySettings MySection = MySettings.Default;
MySection.DBName = "SWH";
MySection.DBPassword = "zx";
MySection.DBServer = "172";
MySection.DBUser = "sini";
По идее после этого в файле App.config должна быть создана наша секция "MySettings" и в ней 4 параметра, заданные выше. Но этой секции в файле App.config нет в помине.
0
31 / 31 / 3
Регистрация: 08.08.2011
Сообщений: 195
19.11.2021, 20:13
Тема древняя, понятное дело. На сегодня можно найти с десяток разных провайдеров. И да, я импонирую serg42 который не постремался таки дать в 2012 году ответ на тему:
Во блин, Вы тут размазали... вместо троттлинга. И соль в том, что даже не в этом суть, хотя его ответ реально перечеркнул троллинг и подтвердил принцип взаимоуважительного общения на форуме, основанного на взаимопомощи. Человек предоставил ответ.
У меня же вопрос: Кто ни будь может на сегодня дать нормально работающий вариант
C#
1
SettingsProvider
при котором, как и при использовании дефолтного
C#
1
LocalFileSettingsProvider
через GUI студии для WindowsForms, ну скажем TextBox, можно было бы в (ApplicationSettings)(PropertyBinding) выбрать связуемый элемент, вместо выпадающей ошибки о ненайденном типе?
Лично я бы был не против возродить данную тему и довести её до логического финала. Вне всякого сомнения - программно всё решается и работает. Притянуть данный вопрос к GUI студии насколько сложно?

Дабы не быть голословным, вот (правда в VB.NET) доработанный вариант типа
VB.NET
1
PortableSettingsProvider
VB.NET
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
Imports System.Configuration
Imports System.Collections.Specialized
Imports System.Xml
 
' https://www.codeproject.com/Articles/20917/Creating-a-Custom-Settings-Provider?fid=472957&df=90&mpp=25&sort=Position&spc=Relaxed&prof=True&view=Normal&fr=26#xx0xx
 
<SettingsProviderAttribute(GetType(PortableSettingsProvider))>
Public Class PortableSettingsProvider
    Inherits SettingsProvider
    Implements IApplicationSettingsProvider
 
#Region " === ПРИВАТНЫЕ ПЕРЕМЕННЫЕ === "
 
    ''' <summary>
    ''' Корневой узел XML
    ''' </summary>
    Private Const SETTINGSROOT As String = "Settings"
 
    ''' <summary>
    ''' XML документ.
    ''' </summary>
    Private _settingsXML As XmlDocument = Nothing
 
#End Region
 
#Region " === ПУБЛИЧНЫЕ СВОЙСТВА === "
 
    ''' <summary>
    ''' Возвращает название продукта (если указано) или имя приложения.
    ''' </summary>
    ''' <returns></returns>
    Public Overrides Property ApplicationName() As String
        Get
            If Application.ProductName.Trim.Length > 0 Then
                Return Application.ProductName
            Else
                Dim fi As New IO.FileInfo(Application.ExecutablePath)
                Return fi.Name.Substring(0, fi.Name.Length - fi.Extension.Length)
            End If
        End Get
        Set(ByVal value As String)
            ' Ничего не делаем
        End Set
    End Property
 
    ''' <summary>
    ''' Только для чтения: Возвращает имя провайдера.
    ''' </summary>
    ''' <returns></returns>
    Public Overrides ReadOnly Property Name() As String
        Get
            Return "PortableSettingsProvider"
        End Get
    End Property
 
    ''' <summary>
    ''' Только для чтения: Открывает или создаёт новый XML документ.
    ''' </summary>
    ''' <returns></returns>
    Private ReadOnly Property SettingsXML() As XmlDocument
        Get
            If _settingsXML Is Nothing Then
                _settingsXML = New XmlDocument()
 
                Try
                    _settingsXML.Load(IO.Path.Combine(GetAppSettingsPath(), GetAppSettingsFilename()))
                Catch ex As Exception
                    ' Создаём новый документ
                    Dim dec As XmlDeclaration = _settingsXML.CreateXmlDeclaration("1.0", "utf-8", String.Empty)
                    _settingsXML.AppendChild(dec)
                    Dim nodeRoot As XmlNode = _settingsXML.CreateNode(XmlNodeType.Element, SETTINGSROOT, "")
                    _settingsXML.AppendChild(nodeRoot)
 
                End Try
            End If
 
            Return _settingsXML
        End Get
    End Property
 
#End Region
 
#Region " === КОНСТРУКТОР ИНИЦИАЛИЗАЦИИ === "
 
    ''' <summary>
    ''' Конструктор инициализации.
    ''' </summary>
    ''' <param name="name">Имя приложения.</param>
    ''' <param name="col">Коллекция связанных ключей и значений (String, String)</param>
    Public Overrides Sub Initialize(ByVal name As String, ByVal col As NameValueCollection)
        MyBase.Initialize(Me.ApplicationName, col)
    End Sub
 
#End Region
 
#Region " === ПРИВАТНЫЕ МЕТОДЫ === "
 
    ''' <summary>
    ''' Ищет среди атрибутов параметр Roaming и возвращает его значение.
    ''' </summary>
    ''' <param name="prop">Объект представляющий метаданные об отдельном свойстве конфигурации.</param>
    ''' <returns></returns>
    Private Function IsRoaming(ByVal prop As SettingsProperty) As Boolean
        For Each d As DictionaryEntry In prop.Attributes
            Dim a As Attribute = DirectCast(d.Value, Attribute)
            If TypeOf a Is System.Configuration.SettingsManageabilityAttribute Then
                Return True
            End If
        Next d
        Return False
    End Function
 
    ''' <summary>
    ''' Получает значение из настроек с учётом параметра Roaming.
    ''' </summary>
    ''' <param name="setting">Объект представляющий метаданные об отдельном свойстве конфигурации.</param>
    ''' <returns></returns>
    Private Function GetValue(ByVal setting As SettingsProperty) As String
        Dim ret As String
 
        Try
            If IsRoaming(setting) Then
                Dim s As XmlNode = SettingsXML.SelectSingleNode(SETTINGSROOT & "/" & setting.Name)
                If IsNothing(s) Then
                    ret = If(IsNothing(setting.DefaultValue), "", setting.DefaultValue.ToString)
                Else
                    ret = s.InnerText
                End If
            Else
                Dim s As XmlNode = SettingsXML.SelectSingleNode(SETTINGSROOT & "/" & Environment.MachineName & "/" & setting.Name)
                If IsNothing(s) Then
                    ret = If(IsNothing(setting.DefaultValue), "", setting.DefaultValue.ToString)
                Else
                    ret = s.InnerText
                End If
            End If
 
        Catch ex As Exception
            ret = If(IsNothing(setting.DefaultValue), "", setting.DefaultValue.ToString)
        End Try
 
        Return ret
    End Function
 
    ''' <summary>
    ''' Устанавливает значение в зависимости от параметра Roaming.
    ''' При True значение сохраняется в корень параметров, в противном случае сохраняется под узлом имени компьютера.
    ''' </summary>
    ''' <param name="propVal">Значение отдельного свойства установок.</param>
    Private Sub SetValue(ByVal propVal As SettingsPropertyValue)
        Dim MachineNode As XmlElement
        Dim SettingNode As XmlElement
 
        Try
            If IsRoaming(propVal.Property) Then
                SettingNode = CType(SettingsXML.SelectSingleNode(SETTINGSROOT & "/" & propVal.Name), XmlElement)
            Else
                SettingNode = CType(SettingsXML.SelectSingleNode(SETTINGSROOT & "/" & Environment.MachineName & "/" & propVal.Name), XmlElement)
            End If
        Catch ex As Exception
            SettingNode = Nothing
        End Try
 
        ' Проверяем существование узла, если существует, то устанавливаем новое значение
        If (SettingNode IsNot Nothing) Then
            SettingNode.InnerText = propVal.SerializedValue.ToString()
        Else
            If IsRoaming(propVal.Property) Then
                'Сохраняем значение как элемент корневого узла настроек
                SettingNode = SettingsXML.CreateElement(propVal.Name)
                SettingNode.InnerText = propVal.SerializedValue.ToString()
                SettingsXML.SelectSingleNode(SETTINGSROOT).AppendChild(SettingNode)
            Else
                ' Зависит от машины, хранится как элемент узла имени компьютера
                Try
                    MachineNode = CType(SettingsXML.SelectSingleNode(SETTINGSROOT & "/" & Environment.MachineName), XmlElement)
                Catch ex As Exception
                    ' Создаём новый узел имени компьютера
                    MachineNode = SettingsXML.CreateElement(Environment.MachineName)
                    SettingsXML.SelectSingleNode(SETTINGSROOT).AppendChild(MachineNode)
                End Try
 
                If MachineNode Is Nothing Then
                    MachineNode = SettingsXML.CreateElement(Environment.MachineName)
                    SettingsXML.SelectSingleNode(SETTINGSROOT).AppendChild(MachineNode)
                End If
 
                SettingNode = SettingsXML.CreateElement(propVal.Name)
                SettingNode.InnerText = propVal.SerializedValue.ToString()
                MachineNode.AppendChild(SettingNode)
            End If
        End If
    End Sub
 
#End Region
 
#Region " === ПУБЛИЧНЫЕ МЕТОДЫ === "
 
    ''' <summary>
    ''' Возвращает каталог расположения сборки.
    ''' </summary>
    ''' <returns></returns>
    Public Overridable Function GetAppSettingsPath() As String
        Dim fi As New System.IO.FileInfo(Application.ExecutablePath)
        Return fi.DirectoryName
    End Function
 
    ''' <summary>
    ''' Возвращает имя файла для хранения настроек.
    ''' </summary>
    ''' <returns></returns>
    Public Overridable Function GetAppSettingsFilename() As String
        Return ApplicationName & ".settings"
    End Function
 
    ''' <summary>
    ''' Просматривает и сохраняет необходимые настройки в файл.
    ''' </summary>
    ''' <param name="context">Контекстная информация о параметрах.</param>
    ''' <param name="propvals">Коллекция значений свойств конфигурации.</param>
    Public Overrides Sub SetPropertyValues(ByVal context As SettingsContext, ByVal propvals As SettingsPropertyValueCollection)
        For Each propval As SettingsPropertyValue In propvals
            SetValue(propval)
        Next propval
 
        Try
            SettingsXML.Save(IO.Path.Combine(GetAppSettingsPath(), GetAppSettingsFilename()))
        Catch ex As Exception
            ' Игнорируем невозможность сохранения параметров
        End Try
    End Sub
 
    ''' <summary>
    ''' Создаёт новую коллекцию значений.
    ''' </summary>
    ''' <param name="context">Контекстная информация о параметрах.</param>
    ''' <param name="props">Коллекция объектов свойств конфигурации.</param>
    ''' <returns></returns>
    Public Overrides Function GetPropertyValues(ByVal context As SettingsContext, ByVal props As SettingsPropertyCollection) As SettingsPropertyValueCollection
        Dim values As New SettingsPropertyValueCollection()
 
        ' Перебираем коллекцию свойств
        For Each setting As SettingsProperty In props
            Dim value As New SettingsPropertyValue(setting) With {.IsDirty = False, .SerializedValue = GetValue(setting)}
            values.Add(value)
        Next setting
        Return values
    End Function
 
    ''' <summary>
    ''' Возвращает установки, связанные с указанным приложением к значениям по умолчанию.
    ''' </summary>
    ''' <param name="context">Контекстная информация о параметрах.</param>
    Public Sub Reset(ByVal context As SettingsContext) Implements IApplicationSettingsProvider.Reset
        _settingsXML = Nothing
    End Sub
 
    ''' <summary>
    ''' Возвращает предыдущую версию конфигурации.
    ''' В данном исполнении не поддерживается.
    ''' </summary>
    ''' <param name="context">Контекстная информация о параметрах.</param>
    ''' <param name="[property]">Объект представляющий метаданные об отдельном свойстве конфигурации.</param>
    ''' <returns></returns>
    Public Function GetPreviousVersion(ByVal context As SettingsContext, ByVal [property] As SettingsProperty) As SettingsPropertyValue Implements IApplicationSettingsProvider.GetPreviousVersion
        Throw New NotImplementedException("Не поддерживается.")
    End Function
 
    ''' <summary>
    ''' Обновляет крайнюю версию конфигурации до текущей версии.
    ''' В данном исполнении не поддерживается.
    ''' </summary>
    ''' <param name="context">Контекстная информация о параметрах.</param>
    ''' <param name="properties">Коллекция объектов свойств конфигурации.</param>
    Public Sub Upgrade(ByVal context As SettingsContext, ByVal properties As SettingsPropertyCollection) Implements IApplicationSettingsProvider.Upgrade
        Throw New NotImplementedException("Не поддерживается.")
    End Sub
 
#End Region
 
End Class
 
Public Class U3SettingsProvider
    Inherits PortableSettingsProvider
 
    Private Const U3APPDATAPATH As String = "U3_APP_DATA_PATH"
 
    ''' <summary>
    ''' Возвращает переменную среды, установленную приложением U3 для указателя на его данные.
    ''' </summary>
    ''' <returns></returns>
    Overrides Function GetAppSettingsPath() As String
        Try
            Return System.Environment.GetEnvironmentVariable(U3APPDATAPATH)
        Catch ex As Exception
            ' Не работает в среде U3, просто возвращаем путь к приложению
            Return MyBase.GetAppSettingsPath
        End Try
    End Function
End Class
Перевёл в C# но, работоспособность не гарантирую, поскольку только пытаюсь пересеть...

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
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
using System.Configuration;
using System.Collections.Specialized;
using System.Xml;
 
// https://www.codeproject.com/Articles/20917/Creating-a-Custom-Settings-Provider?fid=472957&df=90&mpp=25&sort=Position&spc=Relaxed&prof=True&view=Normal&fr=26#xx0xx
 
[SettingsProviderAttribute(typeof(PortableSettingsProvider))]
public class PortableSettingsProvider : SettingsProvider, IApplicationSettingsProvider
{
#region  === ПРИВАТНЫЕ ПЕРЕМЕННЫЕ === 
 
    /// <summary>
    /// Корневой узел XML
    /// </summary>
    private const string SETTINGSROOT = "Settings";
 
    /// <summary>
    /// XML документ.
    /// </summary>
    private XmlDocument _settingsXML = null;
 
#endregion
 
#region  === ПУБЛИЧНЫЕ СВОЙСТВА === 
 
    /// <summary>
    /// Возвращает название продукта (если указано) или имя приложения.
    /// </summary>
    /// <returns></returns>
    public override string ApplicationName
    {
        get
        {
            if (Application.ProductName.Trim.Length > 0)
            {
                return Application.ProductName;
            }
            else
            {
                System.IO.FileInfo fi = new System.IO.FileInfo(Application.ExecutablePath);
                return fi.Name.Substring(0, fi.Name.Length - fi.Extension.Length);
            }
        }
        set
        {
            // Ничего не делаем
        }
    }
 
    /// <summary>
    /// Только для чтения: Возвращает имя провайдера.
    /// </summary>
    /// <returns></returns>
    public override string Name
    {
        get
        {
            return "PortableSettingsProvider";
        }
    }
 
    /// <summary>
    /// Только для чтения: Открывает или создаёт новый XML документ.
    /// </summary>
    /// <returns></returns>
    private XmlDocument SettingsXML
    {
        get
        {
            if (_settingsXML == null)
            {
                _settingsXML = new XmlDocument();
 
                try
                {
                    _settingsXML.Load(System.IO.Path.Combine(GetAppSettingsPath(), GetAppSettingsFilename()));
                }
                catch (Exception ex)
                {
                    // Создаём новый документ
                    XmlDeclaration dec = _settingsXML.CreateXmlDeclaration("1.0", "utf-8", string.Empty);
                    _settingsXML.AppendChild(dec);
                    XmlNode nodeRoot = _settingsXML.CreateNode(XmlNodeType.Element, SETTINGSROOT, "");
                    _settingsXML.AppendChild(nodeRoot);
 
                }
            }
 
            return _settingsXML;
        }
    }
 
#endregion
 
#region  === КОНСТРУКТОР ИНИЦИАЛИЗАЦИИ === 
 
    /// <summary>
    /// Конструктор инициализации.
    /// </summary>
    /// <param name="name">Имя приложения.</param>
    /// <param name="col">Коллекция связанных ключей и значений (String, String)</param>
    public override void Initialize(string name, NameValueCollection col)
    {
        base.Initialize(this.ApplicationName, col);
    }
 
#endregion
 
#region  === ПРИВАТНЫЕ МЕТОДЫ === 
 
    /// <summary>
    /// Ищет среди атрибутов параметр Roaming и возвращает его значение.
    /// </summary>
    /// <param name="prop">Объект представляющий метаданные об отдельном свойстве конфигурации.</param>
    /// <returns></returns>
    private bool IsRoaming(SettingsProperty prop)
    {
        foreach (DictionaryEntry d in prop.Attributes)
        {
            Attribute a = (Attribute)d.Value;
            if (a is System.Configuration.SettingsManageabilityAttribute)
            {
                return true;
            }
        }
        return false;
    }
 
    /// <summary>
    /// Получает значение из настроек с учётом параметра Roaming.
    /// </summary>
    /// <param name="setting">Объект представляющий метаданные об отдельном свойстве конфигурации.</param>
    /// <returns></returns>
    private string GetValue(SettingsProperty setting)
    {
        string ret = null;
 
        try
        {
            if (IsRoaming(setting))
            {
                XmlNode s = SettingsXML.SelectSingleNode(SETTINGSROOT + "/" + setting.Name);
                if ((s == null))
                {
                    ret = (setting.DefaultValue == null) ? "" : setting.DefaultValue.ToString();
                }
                else
                {
                    ret = s.InnerText;
                }
            }
            else
            {
                XmlNode s = SettingsXML.SelectSingleNode(SETTINGSROOT + "/" + Environment.MachineName + "/" + setting.Name);
                if ((s == null))
                {
                    ret = (setting.DefaultValue == null) ? "" : setting.DefaultValue.ToString();
                }
                else
                {
                    ret = s.InnerText;
                }
            }
 
        }
        catch (Exception ex)
        {
            ret = (setting.DefaultValue == null) ? "" : setting.DefaultValue.ToString();
        }
 
        return ret;
    }
 
    /// <summary>
    /// Устанавливает значение в зависимости от параметра Roaming.
    /// При True значение сохраняется в корень параметров, в противном случае сохраняется под узлом имени компьютера.
    /// </summary>
    /// <param name="propVal">Значение отдельного свойства установок.</param>
    private void SetValue(SettingsPropertyValue propVal)
    {
        XmlElement MachineNode = null;
        XmlElement SettingNode = null;
 
        try
        {
            if (IsRoaming(propVal.Property))
            {
                SettingNode = (XmlElement)SettingsXML.SelectSingleNode(SETTINGSROOT + "/" + propVal.Name);
            }
            else
            {
                SettingNode = (XmlElement)SettingsXML.SelectSingleNode(SETTINGSROOT + "/" + Environment.MachineName + "/" + propVal.Name);
            }
        }
        catch (Exception ex)
        {
            SettingNode = null;
        }
 
        // Проверяем существование узла, если существует, то устанавливаем новое значение
        if (SettingNode != null)
        {
            SettingNode.InnerText = propVal.SerializedValue.ToString();
        }
        else
        {
            if (IsRoaming(propVal.Property))
            {
                //Сохраняем значение как элемент корневого узла настроек
                SettingNode = SettingsXML.CreateElement(propVal.Name);
                SettingNode.InnerText = propVal.SerializedValue.ToString();
                SettingsXML.SelectSingleNode(SETTINGSROOT).AppendChild(SettingNode);
            }
            else
            {
                // Зависит от машины, хранится как элемент узла имени компьютера
                try
                {
                    MachineNode = (XmlElement)SettingsXML.SelectSingleNode(SETTINGSROOT + "/" + Environment.MachineName);
                }
                catch (Exception ex)
                {
                    // Создаём новый узел имени компьютера
                    MachineNode = SettingsXML.CreateElement(Environment.MachineName);
                    SettingsXML.SelectSingleNode(SETTINGSROOT).AppendChild(MachineNode);
                }
 
                if (MachineNode == null)
                {
                    MachineNode = SettingsXML.CreateElement(Environment.MachineName);
                    SettingsXML.SelectSingleNode(SETTINGSROOT).AppendChild(MachineNode);
                }
 
                SettingNode = SettingsXML.CreateElement(propVal.Name);
                SettingNode.InnerText = propVal.SerializedValue.ToString();
                MachineNode.AppendChild(SettingNode);
            }
        }
    }
 
#endregion
 
#region  === ПУБЛИЧНЫЕ МЕТОДЫ === 
 
    /// <summary>
    /// Возвращает каталог расположения сборки.
    /// </summary>
    /// <returns></returns>
    public virtual string GetAppSettingsPath()
    {
        System.IO.FileInfo fi = new System.IO.FileInfo(Application.ExecutablePath);
        return fi.DirectoryName;
    }
 
    /// <summary>
    /// Возвращает имя файла для хранения настроек.
    /// </summary>
    /// <returns></returns>
    public virtual string GetAppSettingsFilename()
    {
        return ApplicationName + ".settings";
    }
 
    /// <summary>
    /// Просматривает и сохраняет необходимые настройки в файл.
    /// </summary>
    /// <param name="context">Контекстная информация о параметрах.</param>
    /// <param name="propvals">Коллекция значений свойств конфигурации.</param>
    public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection propvals)
    {
        foreach (SettingsPropertyValue propval in propvals)
        {
            SetValue(propval);
        }
 
        try
        {
            SettingsXML.Save(System.IO.Path.Combine(GetAppSettingsPath(), GetAppSettingsFilename()));
        }
        catch (Exception ex)
        {
            // Игнорируем невозможность сохранения параметров
        }
    }
 
    /// <summary>
    /// Создаёт новую коллекцию значений.
    /// </summary>
    /// <param name="context">Контекстная информация о параметрах.</param>
    /// <param name="props">Коллекция объектов свойств конфигурации.</param>
    /// <returns></returns>
    public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection props)
    {
        SettingsPropertyValueCollection values = new SettingsPropertyValueCollection();
 
        // Перебираем коллекцию свойств
        foreach (SettingsProperty setting in props)
        {
            SettingsPropertyValue value = new SettingsPropertyValue(setting)
            {
                IsDirty = false,
                SerializedValue = GetValue(setting)
            };
            values.Add(value);
        }
        return values;
    }
 
    /// <summary>
    /// Возвращает установки, связанные с указанным приложением к значениям по умолчанию.
    /// </summary>
    /// <param name="context">Контекстная информация о параметрах.</param>
    public void Reset(SettingsContext context)
    {
        _settingsXML = null;
    }
 
    /// <summary>
    /// Возвращает предыдущую версию конфигурации.
    /// В данном исполнении не поддерживается.
    /// </summary>
    /// <param name="context">Контекстная информация о параметрах.</param>
    /// <param name="[property]">Объект представляющий метаданные об отдельном свойстве конфигурации.</param>
    /// <returns></returns>
    public SettingsPropertyValue GetPreviousVersion(SettingsContext context, SettingsProperty property)
    {
        throw new NotImplementedException("Не поддерживается.");
    }
 
    /// <summary>
    /// Обновляет крайнюю версию конфигурации до текущей версии.
    /// В данном исполнении не поддерживается.
    /// </summary>
    /// <param name="context">Контекстная информация о параметрах.</param>
    /// <param name="properties">Коллекция объектов свойств конфигурации.</param>
    public void Upgrade(SettingsContext context, SettingsPropertyCollection properties)
    {
        throw new NotImplementedException("Не поддерживается.");
    }
 
#endregion
 
}
 
public class U3SettingsProvider : PortableSettingsProvider
{
    private const string U3APPDATAPATH = "U3_APP_DATA_PATH";
 
    /// <summary>
    /// Возвращает переменную среды, установленную приложением U3 для указателя на его данные.
    /// </summary>
    /// <returns></returns>
    public override string GetAppSettingsPath()
    {
        try
        {
            return System.Environment.GetEnvironmentVariable(U3APPDATAPATH);
        }
        catch (Exception ex)
        {
            // Не работает в среде U3, просто возвращаем путь к приложению
            return base.GetAppSettingsPath();
        }
    }
}
Это некая база для обсуждения...
0
31 / 31 / 3
Регистрация: 08.08.2011
Сообщений: 195
20.11.2021, 00:32
Для наглядности прикрепляю два проекта на VB и C#
Единственное - там есть кое какие, можно сказать не самые существенные, изменения в классах...
Вложения
Тип файла: zip C#.zip (39.5 Кб, 3 просмотров)
Тип файла: zip VB.zip (45.2 Кб, 0 просмотров)
0
31 / 31 / 3
Регистрация: 08.08.2011
Сообщений: 195
20.11.2021, 01:30
Добавлено через 42 секунды
Цитата Сообщение от kolorotur Посмотреть сообщение
taras atavin, в .NET есть готовый класс для хранения настроек приложения, по дефолту он сохраняет файл с настройками в /user/AppData/[Manufacturer]/[Product]/[Version]/user.config.
Касательно указанного пути, возможно он и правильный для exe (был в своё время) но для dll имеющей свои параметры, такой подход никак не катит...
Вода утекла. Там + на хэше нынче дела крутятся. (не в обиду, времени действительно утекло добуя)
И, кроме того, даже если сейчас заморочиться более толковыми решениями с поиском текущего user.config для Application то для DLL со своими настройками это представляет то ещё нахлобучивание шапки... Как по мне - эта универсальность и поддержка Update от Microsoft слишком уж школьная программа. За своими настройками следует следить самому программеру, а не пытаться натянуть универсальное на всевозможное. Тем более, что программер сам может создать требуемую инфраструктуру для обновления версий своих Settings-ов в XML. А так - получилось, честно говоря, не то чтобы шикарно. Ни по интерфейсам, ни по наследованию...

Добавлено через 12 минут
Я понимаю стремление исключить проблемы с доступом юзеру туда, куда ему не светит. Понимаю поддержку версионности файлов конфигураций. Но нифига не понимаю отсутствие возможности юзеру влиять на метод сохранения (уж коли идём методом упрощения) файлов туда, куда желается. Подход типа - не устраивает тогда пиши свой провайдер как минимум странен. То есть потрать на разбор чужого кода ещё день, другой, хотя спроси меня через пять лет - я и не вспомню, о чём я разбирался с SettingsProvider. Потому как это буквально должно было быть шаговым выбором - так или так. А не заморочка на пустом месте. И да, плюс ещё проблема с GUI...

Добавлено через 11 минут
Почему не сохранение в нужное место или в MemoryStream с выбором XML или Binary а там уже разберёмся в БД лить или ещё как... Странно... Усложняем в очевидных местах, и пытаемся упростить на действительно интересных, пусть и сложных, но зато реально полезных для личного развития местах...
Я, если честно, ковыряясь в этом нагромождении, параллельно вспомнил потоки из ZX-Spectrum - где любой поток можно было перенаправить в конечное устройство, будь оно средством ввода, вывода или просто захламления памяти... Что то там из RST10 и схожего...

Добавлено через 14 минут
Но разница в том, что у Sincler-а подход расширял возможности скромного ПК, здесь же реализация создаёт лишь реальные трудности и неизбежный повторный код, захламляющий диск и оперативную память, ради следования на пустом месте пусть и правильных правил наследования... А проще никак? Или религия не позволяет?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
20.11.2021, 01:30
Помогаю со студенческими работами здесь

Хранение настроек программы в отдельном файле
Доброго времени суток. У меня такой вопрос: как мне нужно переделать код программы, что бы она создавала файл с настройками, где будет...

Хранение настроек программы для нескольких проектов
Добрый вечер, у меня есть несколько проектов в рамках одного решения(Solution) один из них это обычный Form на нем форма с кнопками которая...

Сериализация или парсить xml? (хранение настроек приложения)
Всем привет! Подскажите, как правильно хранить настройки? Можно: Написать свой парсер и хранить в txt\ini Хранить прямо в...

Хранение настроек программы
Нашёл пример: http://www.vr-online.ru/content/c-sohranenie-parametrov-prilozhenija-2146 Использовал, но тут есть зависимость от версии....

Хранение нескольких вариантов (профилей) настроек программы
Доброго времени. У меня появилась задача хранить несколько профилей настроек программы, и я не совсем уверен как бы это реализовать так что...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
17
Ответ Создать тему
Новые блоги и статьи
Символьное дифференцирование
igorrr37 13.02.2026
/ * Логарифм записывается как: (x-2)log(x^2+2) - означает логарифм (x^2+2) по основанию (x-2). Унарный минус обозначается как ! в-строка - входное арифметическое выражение в инфиксной(обычной). . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL3_image
8Observer8 10.02.2026
Содержание блога Библиотека SDL3_image содержит инструменты для расширенной работы с изображениями. Пошагово создадим проект для загрузки изображения формата PNG с альфа-каналом (с прозрачным. . .
Установка Qt-версии Lazarus IDE в Debian Trixie Xfce
volvo 10.02.2026
В общем, достали меня глюки IDE Лазаруса, собранной с использованием набора виджетов Gtk2 (конкретно: если набирать текст в редакторе и вызвать подсказку через Ctrl+Space, то после закрытия окошка. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru