Search code examples
c#windows-8microsoft-metro

Size for ApplicationDataCompositeValue


I'm porting my published app in Windows Phone, to Win 8. While trying to write to the IsolatedStorage equivalent, ApplicationDataContainer, I get an exception. The exception says

Error : The size of the state manager setting has exceeded the limit

I'm not sure if this is the correct way of using the ApplicationDataContainer.

public void WriteToIsolatedStorage()
    {
        try
        {

            ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
            ApplicationDataCompositeValue composite = new ApplicationDataCompositeValue();

            if (localSettings.Containers.ContainsKey("LoveCycleSetting"))
            {
                localSettings.DeleteContainer("LoveCycleSetting");
            }

            composite["GetWeekStart"] = m_bWeekStart;

            composite["iHistCount"] = m_iHistCount;

            composite["dtHistory"] = this.DateTimeToString(m_dtHistory);

            composite["avgCycleTime"] = m_iAvgCycleTime;
       }
    }

The exception occurs at the second last line. m_dtHistory is a string array of size 400. So does the ApplicationDataCompositeValue have a fixed size? Or do I have to write the m_dtHistory array into a file? Cuz in WindowsPhone I could directly write the array into the IsolatedStorageSettings.

It would be really helpful if someone could guide me on this or give links.

Alfah


Solution

  • Yes, ironically settings storage is easier on the phone than WinRT. You can just serialize to a file instead. Here is what I did (partially copied from the code already in SuspensionManager.cs), which works for both value and reference types.

        internal static async Task<bool> SaveSetting(string Key, Object value)
        {
            var ms = new MemoryStream();
            DataContractSerializer serializer = new DataContractSerializer(value.GetType());
            serializer.WriteObject(ms, value);
            await ms.FlushAsync();
    
            // Uncomment this to preview the contents being written
            /*char[] buffer = new char[ms.Length];
            ms.Seek(0, SeekOrigin.Begin);
            var sr = new StreamReader(ms);
            sr.Read(buffer, 0, (int)ms.Length);*/
    
            ms.Seek(0, SeekOrigin.Begin);
            StorageFile file = await ApplicationData.Current.LocalFolder.CreateFileAsync(Key, CreationCollisionOption.ReplaceExisting);
            using (Stream fileStream = await file.OpenStreamForWriteAsync())
            {
                await ms.CopyToAsync(fileStream);
                await fileStream.FlushAsync();
            }
            return true;
        }
    
        // Necessary to pass back both the result and status from an async function since you  can't pass by ref
        internal class ReadResults
        {
            public bool Success { get; set; }
            public Object Result { get; set; }
        }
        internal async static Task<ReadResults> ReadSetting<type>(string Key, Type t)
        {
            var rr = new ReadResults();
    
            try
            {
                var ms = new MemoryStream();
                DataContractSerializer serializer = new DataContractSerializer(t);
    
                StorageFile file = await ApplicationData.Current.LocalFolder.GetFileAsync(Key);
                using (IInputStream inStream = await file.OpenSequentialReadAsync())
                {
                    rr.Result = (type)serializer.ReadObject(inStream.AsStreamForRead());
                }
                rr.Success = true;  
            }
            catch (FileNotFoundException)
            {
                rr.Success = false;
            }
            return rr;
        }