Migrar dados do dicionário de propriedades do aplicativo Xamarin.Forms para preferências do .NET MAUI

Xamarin.Forms possui um dicionário Properties que pode ser usado para armazenar dados e que é acessado usando a propriedade Application.Current.Properties. Esse dicionário usa uma chave string e armazena um valor de object. Os valores no dicionário são salvos no dispositivo quando um aplicativo é pausado ou desligado e carregados quando um aplicativo é reiniciado ou retorna do segundo plano. Para obter mais informações sobre o dicionário de propriedades, veja Dicionário de propriedades.

Ao migrar um aplicativo Xamarin.Forms que armazena dados no dicionário de propriedades do aplicativo para o .NET MAUI, você deve migrar esses dados para as preferências do .NET MAUI. Isso pode ser feito com a classe LegacyApplication e classes auxiliares, apresentadas nesse artigo. Essa classe permite que seu aplicativo .NET MAUI no Android, iOS e Windows leia dados do dicionário de propriedades do aplicativo que foi criado com uma versão anterior do Xamarin.Forms do seu aplicativo. Para obter mais informações sobre as preferências do .NET MAUI, veja Preferências.

Importante

Não há API para acessar o dicionário de propriedades do aplicativo no .NET MAUI.

Acesse dados de propriedades de aplicativos herdados

O código a seguir mostra a classe LegacyApplication, que fornece acesso aos dados de propriedades do aplicativo criados pelo seu aplicativo Xamarin.Forms:

Observação

Para usar esse código, adicione-o a uma classe chamada LegacyApplication em seu projeto de aplicativo .NET MAUI.

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

No Android, a classe LegacyApplication usa a classe PropertiesDeserializer para desserializar dados do arquivo de dicionário de propriedades do aplicativo. O código a seguir mostra a classe PropertiesDeserializer:

Observação

Para usar esse código, adicione-o a uma classe chamada PropertiesDeserializer na pasta Platforms\Android do seu projeto de aplicativo .NET MAUI.

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

No iOS, a classe LegacyApplication usa a classe PropertiesDeserializer para desserializar dados do arquivo de dicionário de propriedades do aplicativo. O código a seguir mostra a classe PropertiesDeserializer:

Observação

Para usar esse código, adicione-o a uma classe chamada PropertiesDeserializer na pasta Platforms\iOS do seu projeto de aplicativo .NET MAUI.

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

No Windows, a classe LegacyApplication usa a classe PropertiesDeserializer para desserializar dados do arquivo de dicionário de propriedades do aplicativo. O código a seguir mostra a classe PropertiesDeserializer:

Observação

Para usar esse código, adicione-o a uma classe chamada PropertiesDeserializer na pasta Platforms\Windows do seu projeto de aplicativo .NET MAUI.

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);
        }
    }
}

Essa versão do Windows da classe PropertiesDeserializer requer o método DontSync extensão. O código a seguir mostra esse método de extensão:

Observação

Para usar esse código, adicione-o a uma classe chamada Extensions na pasta Platforms\Windows do seu projeto de aplicativo .NET MAUI.

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);
    }
}

Consumir dados de propriedades de aplicativos herdados

A classe LegacyApplication pode ser usada para consumir dados do dicionário de propriedades do aplicativo, no Android, iOS e Windows, que foi criado com uma versão anterior do Xamarin.Forms do seu aplicativo:

#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

Esse exemplo mostra o uso da classe LegacyApplication para ler um valor do dicionário de propriedades do aplicativo e, em seguida, gravar o valor nas preferências do .NET MAUI.

Importante

Sempre verifique a presença da chave no dicionário de propriedades do aplicativo antes de acessá-lo, para evitar erros inesperados.