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 の基本設定の詳細については、「基本設定」をご覧ください。

重要

.NET MAUI のアプリ プロパティ ディクショナリにアクセスするための API はありません。

従来のアプリのプロパティ データにアクセスする

次のコードは、Xamarin.Forms アプリで作成されたアプリ プロパティ データへのアクセスを提供する LegacyApplication クラスを示しています。

Note

このコードを使用するには、.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 クラスを示しています。

Note

このコードを使用するには、.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 クラスを示しています。

Note

このコードを使用するには、.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 クラスを示しています。

Note

このコードを使用するには、.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);
        }
    }
}

この Windows バージョンの PropertiesDeserializer クラスには、DontSync 拡張メソッドが必要です。 以下のコード例は、この拡張メソッドを示しています。

Note

このコードを使用するには、.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 基本設定に書き込む方法を示しています。

重要

予期しないエラーを回避するために、必ずアプリ プロパティ ディクショナリにキーが存在することを確認してからアクセスしてください。