将数据从 Xamarin.Forms 应用属性字典迁移到 .NET MAUI 首选项

Xamarin.Forms 具有一个可用于存储数据的 Properties 字典,可使用 Application.Current.Properties 属性对其访问。 该字典使用 string 密钥并存储 object 值。 当应用暂停或关闭时,字典中的值将保存到设备,并在应用重新启动或从后台返回时加载。 有关属性字典的详细信息,请参阅属性字典

在将在应用属性字典中存储数据的 Xamarin.Forms 应用迁移到 .NET MAUI 时,应当将此数据迁移到 .NET MAUI 首选项。 这可以通过本文中介绍的 LegacyApplication 类和帮助程序类实现。 此类可以让 Android、iOS 和 Windows 上的 .NET MAUI 应用从通过应用以前的 Xamarin.Forms 版本创建的应用属性字典读取数据。 有关 .NET MAUI 首选项的详细信息,请参阅 首选项

重要说明

没有 API 可以访问 .NET MAUI 中的应用属性字典。

访问旧版应用属性数据

以下代码显示了 LegacyApplication 类,通过此类可以访问通过 Xamarin.Forms 应用创建的应用属性数据:

注意

要使用此代码,请将其添加到 .NET MAUI 应用项目中名为 LegacyApplication 的类。

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

在 Android 上,LegacyApplication 类使用 PropertiesDeserializer 类反序列化应用属性字典文件中的数据。 以下代码显示 PropertiesDeserializer 类:

注意

要使用此代码,请将其添加到 .NET MAUI 应用项目的 Platforms\Android 文件夹中名为 PropertiesDeserializer 的类。

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

在 iOS 上,LegacyApplication 类使用 PropertiesDeserializer 类反序列化应用属性字典文件中的数据。 以下代码显示 PropertiesDeserializer 类:

注意

要使用此代码,请将其添加到 .NET MAUI 应用项目的 Platforms\iOS 文件夹中名为 PropertiesDeserializer 的类。

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

在 Windows 上,LegacyApplication 类使用 PropertiesDeserializer 类反序列化应用属性字典文件中的数据。 以下代码显示 PropertiesDeserializer 类:

注意

要使用此代码,请将其添加到 .NET MAUI 应用项目的 Platforms\Windows 文件夹中名为 PropertiesDeserializer 的类。

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

PropertiesDeserializer 类的此 Windows 版本需要使用 DontSync 扩展方法。 下面代码展示了此扩展方法:

注意

要使用此代码,请将其添加到 .NET MAUI 应用项目 Platforms\Windows 文件夹中名为 Extensions 的类。

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

使用旧版应用属性数据

LegacyApplication 类可用于使用 Android、iOS 和 Windows 上通过应用以前的 Xamarin.Forms 版本创建的应用属性字典中的数据:

#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

此示例展示如何使用 LegacyApplication 类从应用属性字典中读取值,然后将该值写入 .NET MAUI 首选项。

重要说明

请务必首先检查应用属性字典中是否存在密钥,然后再访问它,以防止发生意外错误。