2014年8月24日 星期日

Store Apps 操作應用程式內設定值

在傳統 Windows 應用程式開發時,我們使用 Registry 儲存 Key Value 形式的資料,對於作業系統的資訊,我們也直接讀取 Registry 中的值,但在 Store Apps 的框架下,不論是 Windows 還是 Windows Phone 的應用程式,儲存資料方面我們需要用到 ApplicationData 類別在應用程式的私有空間中存取資訊,且我們無法進行 Registry 操作,僅能透過 SDK 所提供的 API 調查詢系統資訊。

這裡記錄如何在 Store Apps 中使用 ApplicationData 存取 Windows 與 Windows Phone 平台上的 Key Value 形式資訊,假設我們想要將用戶登入的帳號儲存下來,並在每次開啟時自動替它在登入頁填入帳號,在 Universal Apps 下兩個平台的方式都相同,最簡單的方式可以依下面的範例撰寫。

private void OnPageLoaded(object sender, RoutedEventArgs e)
{
    const String SETTING_USER_ID_KEY = "UserId";
    ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
    Object value = localSettings.Values[SETTING_USER_ID_KEY];
    if(value != null)
    {
        String userId = value.ToString();
        if (userId.Contains('@'))
        {
            txt_user_id.Text = value.ToString();
        }
        else
        {
            localSettings.Values.Remove(SETTING_USER_ID_KEY);
        }
    }
}

private void HandleLoginSuccess(String userId)
{
    const String SETTING_USER_ID_KEY = "UserId";
    ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
    localSettings.Values[SETTING_USER_ID_KEY] = userId;
}

有時後某些設定的值我們不想拆成三筆來儲存,例如用戶在應用程式中所選擇的字型、尺寸、顏色,我們可以利用 ApplicationDataCompositeValue 來處理,例如。

private void SaveUserFontSettings(FontFamily family, Int32 size, Color color)
{
    const string SETTING_USER_FONT_KEY = "UserFontSetting";
    const string SETTING_USER_FONT_FAMILY_KEY = "Family";
    const string SETTING_USER_FONT_SIZE_KEY = "Size";
    const string SETTING_USER_FONT_COLOR_KEY = "Color";

    ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;

    ApplicationDataCompositeValue composite = new ApplicationDataCompositeValue();
    composite[SETTING_USER_FONT_FAMILY_KEY] = family;
    composite[SETTING_USER_FONT_SIZE_KEY] = size;
    composite[SETTING_USER_FONT_COLOR_KEY] = color;

    localSettings.Values[SETTING_USER_FONT_KEY] = composite;
}

private void LoadUserFontSettings()
{
    const string SETTING_USER_FONT_KEY = "UserFontSetting";
    const string SETTING_USER_FONT_FAMILY_KEY = "Family";
    const string SETTING_USER_FONT_SIZE_KEY = "Size";
    const string SETTING_USER_FONT_COLOR_KEY = "Color";

    ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;

    ApplicationDataCompositeValue composite = localSettings.Values[SETTING_USER_FONT_KEY] as ApplicationDataCompositeValue;
    if (composite != null)
    {
        Debug.WriteLine(composite[SETTING_USER_FONT_FAMILY_KEY]);
        Debug.WriteLine(composite[SETTING_USER_FONT_SIZE_KEY]);
        Debug.WriteLine(composite[SETTING_USER_FONT_COLOR_KEY]);
    }
}


除了上面的方法來儲存複合式的設定值之外,還可以透過建立 ApplicationDataContainer 的方式將邏輯上可歸類的設定值整理在同一層的資料夾下,對於操作 Registry 習慣的開發者來說這種方式大概會比較熟悉。

private void SaveUserData()
{
    ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
    const string SETTING_USER_CONTAINER_KEY = "UserDatas";
    const string SETTING_USER_CONTAINER_ID_KEY = "Id";
    const string SETTING_USER_CONTAINER_PWD_KEY = "Password";
    const string SETTING_USER_CONTAINER_LAST_LOGIN_KEY = "LastLoginTime";

    ApplicationDataContainer container = null;

    if (!localSettings.Containers.TryGetValue("SETTING_USER_CONTAINER_KEY", out container))
    {
        container = localSettings.CreateContainer(SETTING_USER_CONTAINER_KEY, ApplicationDataCreateDisposition.Always);
    }

    container.Values[SETTING_USER_CONTAINER_ID_KEY] = txt_user_id.Text;
    container.Values[SETTING_USER_CONTAINER_PWD_KEY] = GetMD5(txt_user_pwd.Text);
    container.Values[SETTING_USER_CONTAINER_LAST_LOGIN_KEY] = DateTime.UtcNow;
}

private void LoadUserData()
{
    ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
    const string SETTING_USER_CONTAINER_KEY = "UserDatas";
    const string SETTING_USER_CONTAINER_ID_KEY = "Id";
    const string SETTING_USER_CONTAINER_PWD_KEY = "Password";
    const string SETTING_USER_CONTAINER_LAST_LOGIN_KEY = "LastLoginTime";

    ApplicationDataContainer container = null;

    if (localSettings.Containers.TryGetValue("SETTING_USER_CONTAINER_KEY", out container))
    {
        DateTime lastTime = (DateTime) container.Values[SETTING_USER_CONTAINER_LAST_LOGIN_KEY];
        if(DateTime.UtcNow - lastTime > TimeSpan.FromDays(7.0))
        {
            // 一週以上未登入,清空儲存的用戶資料
            localSettings.DeleteContainer(SETTING_USER_CONTAINER_KEY);
            container = localSettings.CreateContainer(SETTING_USER_CONTAINER_KEY, ApplicationDataCreateDisposition.Always);
        }
    }
    else
    {
        container = localSettings.CreateContainer(SETTING_USER_CONTAINER_KEY, ApplicationDataCreateDisposition.Always);
    }

    txt_user_id.Text = container.Values[SETTING_USER_CONTAINER_ID_KEY].ToString();
}

上面所有的範例都是使用 ApplicationData.Current.LocalSettings 這個值,除了 LocalSettings 之外,也可以使用 ApplicationData.Current.RoamingSettings 這個值,操作方法一樣,但資料可以儲存在 Windows 帳戶的雲端上讓不同裝置共用,相當方便。此外,如果是使用 RoamingSettings 來做資料的儲存,甚至有資料修改的事件可以取用,方法如下。

private void SaveSettings()
{
    ApplicationData applicationData = ApplicationData.Current;
    ApplicationDataContainer roamingSettings = applicationData.RoamingSettings;
    applicationData.DataChanged += OnRoamingSettingChanged;
    // Save Setting and Send Event
    applicationData.SignalDataChanged();
}

private void OnRoamingSettingChanged(ApplicationData appData, object o)
{
    // Update Data from Roaming
}


沒有留言:

張貼留言