0

Playing with a simple world clock program has led me to a problem of how to persist a custom ObservableCollection of Clock objects between program runs. I can successfully save other setting types such as Strings, Doubles and Boolean but the ObservableCollection is not saved between program sessions.

No errors are thrown, debugger values appear to be updating fine (Properties.Settings.Default.SavedClocks count increases), and the clocks are added to the displayed list with no problems.

This question has led me to the current structure of code below.


enter image description here


Settings.Designer.cs - Manually created

[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public ObservableCollection<Clock> SavedClocks
{
    get{
        return ((ObservableCollection<Clock>)(this["SavedClocks"]));
    }
    set{
        this["SavedClocks"] = value;
    }
}

Clock class definition

[Serializable]
public class Clock : INotifyPropertyChanged
{
    public string m_LocationName { get; set; }
    public TimeZoneInfo m_TimeZone { get; set; }

    public Clock(){}

    public Clock(TimeZoneInfo tz, string name)
    {
        m_TimeZone = tz;
        m_LocationName = name;
    }

    //.... Other methods removed for brevity
}

Main Window Initialized

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

            if (Properties.Settings.Default.SavedClocks == null)
            {
                Properties.Settings.Default.SavedClocks = new ObservableCollection<Clock>
                {
                    //When list is empty, default with local clock
                    new Clock(System.TimeZoneInfo.Local, System.TimeZoneInfo.Local.StandardName)
                };

                Properties.Settings.Default.Save();
            }

            lvDataBinding.ItemsSource = Properties.Settings.Default.SavedClocks;
        }
    }
}

Adding new clock to observable collection (from drop down list)

private void btn_AddRegion_Click(object sender, RoutedEventArgs e)
{
    TimeZoneInfo tz = timeZoneCombo.SelectedItem as TimeZoneInfo;

    Properties.Settings.Default.SavedClocks.Add(new Clock(tz, tbx_RegionName.Text));
    Properties.Settings.Default.Save();
}

XAML - Don't think any of it would be useful but here is the ListView I'm setting the ItemSource of

<ListView  Name="lvDataBinding">
Community
  • 1
  • 1
Automate This
  • 30,726
  • 11
  • 60
  • 82
  • For storing data, the collection doesn't need to be observable. You could easily initialize an ObservableCollection from a stored List or array during application startup. See also this post about storing custom types in Application Settings: http://www.blackwasp.co.uk/customappsettings.aspx – Clemens Feb 10 '17 at 22:18
  • @Clemens - The post you linked is a good source and I've followed it to the letter but unfortunately it doesn't solve my issue with data not being persistent between runs. Trying a different type is an option but I'm interested in knowing why my approach isn't working as expected. Thks – Automate This Feb 10 '17 at 23:23
  • Your Clock class should probably have a parameterless constructor. – Clemens Feb 10 '17 at 23:29
  • @Clemens - Actually, I have that already but accidentally stripped it out when posting. Posted now. Thanks for the thought – Automate This Feb 11 '17 at 04:00
  • @PortlandRunner Try remove INPC from Clock class. – AnjumSKhan Feb 11 '17 at 04:38

1 Answers1

2

Try to add the SettingsSerializeAs attribute to the SavedClocks property of in Settings.Designer.cs to specify the the collection should be serialized as binary data:

[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.SettingsSerializeAs(System.Configuration.SettingsSerializeAs.Binary)]
[global::System.Configuration.DefaultSettingValueAttribute(null)]
public ObservableCollection<Clock> SavedClocks
{
    get
    {
        return ((ObservableCollection<Clock>)(this["SavedClocks"]));
    }
    set
    {
        this["SavedClocks"] = value;
    }
}
mm8
  • 163,881
  • 10
  • 57
  • 88