Migrate data from the Xamarin.Forms app properties dictionary to .NET MAUI preferences
Xamarin.Forms has a Properties
dictionary that can be used to store data, and which is accessed using the Application.Current.Properties
property. This dictionary uses a string
key and stores an object
value. The values in the dictionary are saved to the device when an app is paused or shut down, and loaded when an app is restarted or returns from the background. For more information about the properties dictionary, see Properties dictionary.
When migrating a Xamarin.Forms app that stores data in the app properties dictionary to .NET MAUI, you should migrate this data to .NET MAUI preferences. This can be accomplished with the LegacyApplication
class, and helper classes, which is presented in this article. This class enables your .NET MAUI app on Android, iOS, and Windows, to read data from the app properties dictionary that was created with a previous Xamarin.Forms version of your app. For more information about .NET MAUI preferences, see Preferences.
Important
There's no API to access the app properties dictionary in .NET MAUI.
Access legacy app properties data
The following code shows the LegacyApplication
class, which provides access to the app properties data created by your Xamarin.Forms app:
Note
To use this code, add it to a class named LegacyApplication
in your .NET MAUI app project.
namespace MigrationHelpers;
public class LegacyApplication
{
readonly PropertiesDeserializer deserializer;
Task<IDictionary<string, object>>? propertiesTask;
static LegacyApplication? current;
public static LegacyApplication? Current
{
get
{
current ??= (LegacyApplication)Activator.CreateInstance(typeof(LegacyApplication));
return current;
}
}
public LegacyApplication()
{
deserializer = new PropertiesDeserializer();
}
public IDictionary<string, object> Properties
{
get
{
propertiesTask ??= GetPropertiesAsync();
return propertiesTask.Result;
}
}
async Task<IDictionary<string, object>> GetPropertiesAsync()
{
IDictionary<string, object> properties = await deserializer.DeserializePropertiesAsync().ConfigureAwait(false);
properties ??= new Dictionary<string, object>(4);
return properties;
}
}
Android
On Android, the LegacyApplication
class uses the PropertiesDeserializer
class to deserialize data from the app properties dictionary file. The following code shows the PropertiesDeserializer
class:
Note
To use this code, add it to a class named PropertiesDeserializer
in the Platforms\Android folder of your .NET MAUI app project.
using System.Diagnostics;
using System.IO.IsolatedStorage;
using System.Runtime.Serialization;
using System.Xml;
namespace MigrationHelpers;
public class PropertiesDeserializer
{
const string PropertyStoreFile = "PropertyStore.forms";
public Task<IDictionary<string, object>> DeserializePropertiesAsync()
{
// Deserialize property dictionary to local storage
return Task.Run(() =>
{
using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
{
if (!store.FileExists(PropertyStoreFile))
return null;
using (IsolatedStorageFileStream stream = store.OpenFile(PropertyStoreFile, FileMode.Open, FileAccess.Read))
using (XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(stream, XmlDictionaryReaderQuotas.Max))
{
if (stream.Length == 0)
return null;
try
{
var dcs = new DataContractSerializer(typeof(Dictionary<string, object>));
return (IDictionary<string, object>)dcs.ReadObject(reader);
}
catch (Exception e)
{
Debug.WriteLine("Could not deserialize properties: " + e.Message);
Console.WriteLine($"PropertyStore Exception while reading Application properties: {e}");
}
}
}
return null;
});
}
}
iOS
On iOS, the LegacyApplication
class uses the PropertiesDeserializer
class to deserialize data from the app properties dictionary file. The following code shows the PropertiesDeserializer
class:
Note
To use this code, add it to a class named PropertiesDeserializer
in the Platforms\iOS folder of your .NET MAUI app project.
using System.Diagnostics;
using System.IO.IsolatedStorage;
using System.Runtime.Serialization;
using System.Xml;
namespace MigrationHelpers;
public class PropertiesDeserializer
{
const string PropertyStoreFile = "PropertyStore.forms";
public Task<IDictionary<string, object>> DeserializePropertiesAsync()
{
// Deserialize property dictionary to local storage
return Task.Run(() =>
{
using (var store = IsolatedStorageFile.GetUserStoreForApplication())
using (var stream = store.OpenFile(PropertyStoreFile, System.IO.FileMode.OpenOrCreate))
using (var reader = XmlDictionaryReader.CreateBinaryReader(stream, XmlDictionaryReaderQuotas.Max))
{
if (stream.Length == 0)
return null;
try
{
var dcs = new DataContractSerializer(typeof(Dictionary<string, object>));
return (IDictionary<string, object>)dcs.ReadObject(reader);
}
catch (Exception e)
{
Debug.WriteLine("Could not deserialize properties: " + e.Message);
Console.WriteLine($"PropertyStore Exception while reading Application properties: {e}");
}
}
return null;
});
}
}
Windows
On Windows, the LegacyApplication
class uses the PropertiesDeserializer
class to deserialize data from the app properties dictionary file. The following code shows the PropertiesDeserializer
class:
Note
To use this code, add it to a class named PropertiesDeserializer
in the Platforms\Windows folder of your .NET MAUI app project.
using System.Diagnostics;
using System.Runtime.Serialization;
using Windows.Storage;
namespace MigrationHelpers;
public class PropertiesDeserializer
{
const string PropertyStoreFile = "PropertyStore.forms";
public async Task<IDictionary<string, object>> DeserializePropertiesAsync()
{
try
{
StorageFile file = await ApplicationData.Current.RoamingFolder.GetFileAsync(PropertyStoreFile).DontSync();
using (Stream stream = (await file.OpenReadAsync().DontSync()).AsStreamForRead())
{
if (stream.Length == 0)
return new Dictionary<string, object>(4);
try
{
var serializer = new DataContractSerializer(typeof(IDictionary<string, object>));
return (IDictionary<string, object>)serializer.ReadObject(stream);
}
catch (Exception e)
{
Debug.WriteLine("Could not deserialize properties: " + e.Message);
Console.WriteLine($"PropertyStore Exception while reading Application properties: {e}");
}
return null;
}
}
catch (FileNotFoundException)
{
return new Dictionary<string, object>(4);
}
}
}
This Windows version of the PropertiesDeserializer
class requires the DontSync
extension method. The following code shows this extension method:
Note
To use this code, add it to a class named Extensions
in the Platforms\Windows folder of your .NET MAUI app project.
using System.Runtime.CompilerServices;
using Windows.Foundation;
namespace MigrationHelpers;
internal static class Extensions
{
public static ConfiguredTaskAwaitable<T> DontSync<T>(this IAsyncOperation<T> self)
{
return self.AsTask().ConfigureAwait(false);
}
}
Consume legacy app property data
The LegacyApplication
class can be used to consume data from the app properties dictionary, on Android, iOS, and Windows, that was created with a previous Xamarin.Forms version of your app:
#if ANDROID || IOS || WINDOWS
using MigrationHelpers;
...
int id;
if (LegacyApplication.Current.Properties.ContainsKey("id"))
{
id = (int)LegacyApplication.Current.Properties["id"];
Preferences.Set("id", id);
}
#endif
This example shows using the LegacyApplication
class to read a value from the app properties dictionary, and then write the value to .NET MAUI preferences.
Important
Always check for the presence of the key in the app properties dictionary before accessing it, to prevent unexpected errors.