Пользовательские настройки читают неверное значение двойного типа
Я пытаюсь создать приложение для редактирования пользовательских настроек и столкнуться со странной проблемой. Я пишу и читаю, используя пользовательские настройки, и он не может прочитать одну из переменных.
public MainWindow()
{
InitializeComponent();
input1.Value = Properties.Settings.Default.input1Setting;
input2.Value = Properties.Settings.Default.input2Setting;
}
private void input1_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
Properties.Settings.Default.input1Setting = Convert.ToDouble(input1.Value);
Properties.Settings.Default.Save();
}
private void input2_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
Properties.Settings.Default.input2Setting = Convert.ToInt16(input2.Value);
Properties.Settings.Default.Save();
}
private void OnlyNumberValidation(object sender, TextCompositionEventArgs e)
{
Regex regex = new Regex("[^0-9]+");
e.Handled = regex.IsMatch(e.Text);
}
и ползунки XAML
<Slider ValueChanged="input1_ValueChanged" IsSnapToTickEnabled="True" TickFrequency="0.25" Minimum="1" Maximum="50" Name="input1" PreviewTextInput="OnlyNumberValidation"/>
<Slider ValueChanged="input2_ValueChanged" IsSnapToTickEnabled="True" TickFrequency="1" Maximum="2000" Minimum="0" Name="input2" PreviewTextInput="OnlyNumberValidation"/>
В редакторе настроек визуальной студии input1 задан как double, input2 как int. Области действия Botch устанавливаются пользователем.
Проблема в том, что только ползунок input2 получает правильное значение. input1 всегда установлен в единицу.
Я попытался добавить MessageBox.Show(Properties.Settings.Default.input1Setting.ToString()) при запуске, и он по-прежнему отображал 1, но значение input1 в app.config (значение в папке project/bin/debug/, один в локальной /company/project/1.0.0/ и в visual studio app.config равен 4)
upd1 Смена 4 на 4.0 не помогла. Все еще меняется на 1.
1 ответ
Выдает минимальное значение input1, отличное от нуля, и значение ValueChanged, устанавливаемое в XAML. Когда ползунки созданы, они по умолчанию имеют нулевое значение, затем события связываются, а затем они настраиваются так, чтобы быть в пределах минимума и максимума.
Это означает, что значение изменяется на 1 на входе 1, а затем происходит событие и сохраняет значение в настройках. Все это происходит во время InitializeComponent и, следовательно, происходит до вашей попытки назначить input1.Value в конструкторе MainWindow.
Опция 1
Есть несколько вариантов, во-первых, это меньше изменений в вашем существующем коде. Удалите привязку ValueChanged из XAML.
<Slider IsSnapToTickEnabled="True" TickFrequency="0.25" Minimum="1" Maximum="50" Name="input1" PreviewTextInput="OnlyNumberValidation"/>
<Slider IsSnapToTickEnabled="True" TickFrequency="1" Maximum="2000" Minimum="0" Name="input2" PreviewTextInput="OnlyNumberValidation"/>
И добавьте их после InitializeComponent, еще лучше добавить их после того, как вы установите значения, чтобы не сохранять существующие значения:
input1.ValueChanged += input1_ValueChanged;
input2.ValueChanged += input2_ValueChanged;
Вариант 2
Но что может быть лучшим вариантом, в зависимости от того, как вы смотрите на вещи, это привязать элементы управления прямо к настройкам, а затем вызывать save только при закрытии формы.
Убедитесь, что у вас есть ключ настроек, поместив его в файл app.xaml. Вам нужно будет добавить пространство имен к атрибутам узла приложения, xmlns: properties = "clr-namespace: WpfApplication1.Properties", а внутри узла Application.Resourses добавить узел свойств. Ниже приведен пример того, как может выглядеть ваш app.xaml (с общими пространствами имен):
<Application x:Class="WpfApplication1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
xmlns:properties="clr-namespace:WpfApplication1.Properties"
StartupUri="MainWindow.xaml">
<Application.Resources>
<properties:Settings x:Key="Settings" />
</Application.Resources>
</Application>
Теперь вернитесь в свой MainWindow.xaml, удалите ValueChanged (как в примере выше) и добавьте свойство Value, привязав его к значению настроек:
<Slider IsSnapToTickEnabled="True" TickFrequency="0.25" Minimum="1" Maximum="50" Name="input1" Value="{Binding Source={StaticResource Settings}, Path=Default.input1Setting}" PreviewTextInput="OnlyNumberValidation"/>
<Slider IsSnapToTickEnabled="True" TickFrequency="1" Maximum="2000" Minimum="0" Name="input2" Value="{Binding Source={StaticResource Settings}, Path=Default.input2Setting}" PreviewTextInput="OnlyNumberValidation"/>
И в вашем файле MainWindow.xaml.cs вы модифицируете его так:
public MainWindow()
{
InitializeComponent();
Closing += MainWindow_Closing;
}
private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
Properties.Settings.Default.Save();
}
private void OnlyNumberValidation(object sender, TextCompositionEventArgs e)
{
Regex regex = new Regex("[^0-9]+");
e.Handled = regex.IsMatch(e.Text);
}
Конечно, если вы предпочитаете связывать свои события в XAML, вы можете пропустить Closing += MainWindow_Closing; в файле MainWindow.xaml.cs и вместо этого добавьте этот атрибут Closing="MainWindow_Closing" в узел Window MainWindow.xaml.
Мне нравится вариант 2, потому что он сохраняется только один раз, хотя значения Settings.Default всегда доступны на основе значения ползунков, вам нужно только сохранить его, чтобы он был доступен при следующем запуске.
Попробуйте это и посмотрите, какой из них вам больше нравится.