2016-08-19 2 views
-1

У меня есть следующие:Почему не сохраняются мои пользовательские настройки, связанные с данными?

MainWindow:

<Window x:Class="TestApp.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:local="clr-namespace:TestApp" 
     xmlns:settings="clr-namespace:TestApp.Settings" 
     mc:Ignorable="d" Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
     <ItemsControl> 
      <ItemsControl.ItemsSource> 
       <Binding> 
        <Binding.Source> 
         <CollectionViewSource Source="{Binding Source={x:Static settings:CustomSettings.Default}, Path=coll}" /> 
        </Binding.Source> 
       </Binding> 
      </ItemsControl.ItemsSource> 

      <ItemsControl.ItemTemplate> 
       <DataTemplate> 
        <Grid> 
         <Grid.ColumnDefinitions> 
          <ColumnDefinition Width="100" /> 
          <ColumnDefinition Width="100" /> 
         </Grid.ColumnDefinitions> 

         <TextBox Text="{Binding Name}" /> 
         <Button Grid.Column="1" Click="Button_Click" /> 
        </Grid> 
       </DataTemplate> 
      </ItemsControl.ItemTemplate> 
     </ItemsControl> 
    </Grid> 
</Window> 

Code-Behind:

using System.Collections.ObjectModel; 
using System.ComponentModel; 
using System.Runtime.CompilerServices; 
using System.Windows; 

namespace TestApp 
{ 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 

      if (Settings.CustomSettings.Default.coll == null) 
      { 
       Settings.CustomSettings.Default.coll = new ObservableCollection<BasicClass>(); 
       Settings.CustomSettings.Default.coll.Add(new BasicClass("String1")); 
       Settings.CustomSettings.Default.coll.Add(new BasicClass("String2")); 
       Settings.CustomSettings.Default.coll.Add(new BasicClass("String3")); 
      } 

      Settings.CustomSettings.Default.Save(); 
     } 

     private void Button_Click(object sender, RoutedEventArgs e) 
     { 
      Settings.CustomSettings.Default.Save(); 

      foreach (BasicClass item in Settings.CustomSettings.Default.coll) 
      { 
       MessageBox.Show(item.Name); 
      } 
     } 
    } 

    public class BasicClass : INotifyPropertyChanged 
    { 
     public event PropertyChangedEventHandler PropertyChanged; 

     private void NotifyPropertyChanged([CallerMemberName] string propertyName = "") 
     { 
      if (PropertyChanged != null) 
      { 
       PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
      } 
     } 

     private string name; 
     public string Name 
     { 
      get { return name; } 
      set 
      { 
       if (value != name) 
       { 
        name = value; 
        NotifyPropertyChanged("Name"); 
       } 
      } 
     } 

     public BasicClass() { } 

     public BasicClass(string Name) 
     { 
      this.Name = Name; 
     } 
    } 
} 

Настройки:

using System.Collections.ObjectModel; 
using System.Configuration; 
using System.Diagnostics; 

namespace TestApp.Settings 
{ 
    internal sealed partial class CustomSettings : ApplicationSettingsBase 
    { 
     private static CustomSettings defaultInstance = ((CustomSettings)(Synchronized(new CustomSettings()))); 

     public static CustomSettings Default 
     { 
      get 
      { 
       return defaultInstance; 
      } 
     } 

     [UserScopedSetting()] 
     [DebuggerNonUserCode()] 
     public ObservableCollection<BasicClass> coll 
     { 
      get 
      { 
       return ((ObservableCollection<BasicClass>)(this["coll"])); 
      } 
      set 
      { 
       this["coll"] = value; 
      } 
     } 
    } 
} 

Как это работает:

Приложение представляет три элемента управления, состоящих из TextBox и Button. Они являются частью ItemsControl, источник которой привязан к пользовательской настройке «coll», типа ObservableCollection<BasicClass>. BasicClass имеет одно свойство, 'Name', которое появляется в TextBox посредством привязки данных.

Ожидаемое поведение:

изменить текст в TextBox, а затем нажмите на соответствующую Button. Затем это сохранит новое значение в 'coll', а затем представит последовательность MessageBox, демонстрирующую, что это действительно было изменено. Я перезапускаю приложение, и мое значение показывает вновь сохраненное значение.

Фактическое поведение:

изменить текст, я нажимаю Button, то MessageBox последовательность показывает мне, что значение будет сохранено в настройках пользователя (и должны, следовательно, было сохранено). Однако, когда я перезапускаю приложение, я вижу исходное значение, а не сохраненное.

Аномалия (?):

Если я нажимаю на кнопку два раза, а не один раз (идя через MessageBox последовательности дважды), когда я перезагружать значение в настоящее время успешно сохранены.

+0

Пожалуйста, вернитесь и прочитайте страницу [mcve]. Как и в предыдущем вопросе, этот, как представляется, содержит гораздо больше кода, чем на самом деле требуется для воспроизведения вашей проблемы. Например, действительно ли правда, что эта проблема возникает только тогда, когда вы используете 'WrapPanel' для вашего' ItemsControl'? Я серьезно сомневаюсь в этом. В вашем посте есть много других примеров такого постороннего кода. Пожалуйста, предоставьте хороший MCVE, если вы хотите, чтобы кто-то помог вам отладить ваш код. –

ответ

1

EDIT (оригинальный ответ ниже):

Хотя я подозреваю реализации IBindableComponent на подклассе ObservableCollection мощь работы, я не рекомендую. Если вы просто сохраняете строки, System.Collections.Specialized.StringCollection может вам помочь.

Но в целом, я не думаю, что имеет смысл обновлять настройки своего приложения каждый раз, когда что-то меняется. Вместо этого загрузите их во время запуска приложения в свою модель просмотра (например, ObservableCollection) и переместите их обратно к настройкам приложения при закрытии. Таким образом, значения нужно только десериализовать и сериализовать один раз.

Эффект, который вы упомянули в своем комментарии о настройке значения для себя, работает (кажется), потому что список повторно сериализуется при его настройке. Похоже, ApplicationSettingsBase хранит сериализованную копию каждого предоставленного вами значения и поэтому не может реагировать на изменения исходного объекта. Когда вы снова предоставляете значение, он перезаписывает свою копию сериализованной версией нового состояния вашего объекта. Однако, если вы сериализуете список каждый раз, когда пользователь вносит изменения, это повлияет на производительность вашего приложения, как только список станет длиннее.

Это может быть интересно для вас, а также: How to store int[] array in application Settings

И это кажется ненужным подклассу ApplicationSettingsBase себя, см https://social.msdn.microsoft.com/Forums/en-US/4e299ed8-8e3a-408e-b900-eb6738fe0775/persist-and-restore-application-state?forum=wpf

ORIGINAL:

Я не знаком с ApplicationSettingsBase, но возможно, это помогает https://msdn.microsoft.com/en-in/library/8eyb2ct1(en-us).aspx:

Вы можете o привязать параметр приложения к компоненту, который поддерживает интерфейс IBindableComponent. Кроме того, компонент должен реализовать событие изменения для определенного свойства привязки или сообщить параметры приложения, которые свойство изменило с помощью интерфейса INotifyPropertyChanged. Если компонент не реализует IBindableComponent и вы привязываетесь через Visual Studio, связанные свойства будут установлены в первый раз, но не будут обновлены. Если компонент реализует IBindableComponent, но не поддерживает уведомления об изменении свойств, привязка не будет обновляться в файле настроек при изменении свойства.

Похоже, что это связано с тем, что сохранены только сериализованные версии ваших настроек, поэтому изменения в списке не распознаются (поскольку сама ссылка не изменяется). Обратите внимание, что когда вы полностью заменяете список нажатием кнопки, значения нового списка сохраняются.

+0

Спасибо, это кажется правильным. Итак, где мне нужно реализовать «IBindableComponent»? На 'ObservableCollection'? На 'CollectionViewSource'? Когда вы говорите, что сама ссылка не меняется, о какой ссылке вы говорите? Интересно, что добавление 'Settings.CustomSettings.Default.coll = Settings.CustomSettings.Default.coll;' перед 'Settings.CustomSettings.Default.Save();' исправляет проблему, но, конечно, это похоже на взлома. –

+0

@ChrisMack, пожалуйста, просмотрите мой обновленный ответ. Я думаю, вы должны подойти к проблеме немного по-другому. – doubleYou

Смежные вопросы