在帧之间共享会话数据并支持加载/恢复状态

时间:2013-12-30 20:19:31

标签: c# wpf windows-phone-7 windows-phone-8 windows-store-apps

假设我在带有会话数据的Windows应用商店应用程序的主框架中有一个列表。单击某个项目时,将打开一个新框架,我可以在其中编辑数据。

如何在帧之间正确共享会话数据,以及如何保存和恢复会话数据以使对象之间的引用完好无损?

我知道在创建新帧时我可以将对象作为参数发送。我也知道如何保存/恢复会话数据。我只是不知道如何解决这个问题:)。

3 个答案:

答案 0 :(得分:1)

您可以使用NavigationService将数据发送到新帧,如下面的选项中所述。它更像是发送keyvalur对作为uri参数:

NavigationService.Navigate(new Uri("/Page1.xaml?parameter1=p1&parameter2=p2", UriKind.Relative));

获得价值:

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
    base.OnNavigatedTo(e);  
    string parameterValue = NavigationContext.QueryString["parameter"];  
}

http://www.geekchamp.com/tips/how-to-pass-data-between-pages-in-windows-phone-alternatives

此外,如果您想共享复杂的对象,您可能需要创建嵌套的视图模型,但如果由于视图的性质而没有奢侈的嵌套视图模型,那么您可能需要创建静态应用缓存以使用介质来保持/在框架之间共享对象。

答案 1 :(得分:1)

存储对象的全局引用并不是那么棘手。你可以拥有一个静态的持有者,他或她没有责任坚持下去。哦,像这样:

public interface IViewModel { }
public class ViewModelOne : IViewModel { }
public class ViewModelTwo : IViewModel { }
public class ViewModelThree : IViewModel { }
public static class GlobalObjects
{
    private static ViewModelOne viewModelOne = null;
    public static ViewModelOne ViewModelOne
    {
        get { return Get<ViewModelOne>(ref viewModelOne); }
        set { Set(ref viewModelOne, value); }
    }

    private static T Get<T>(ref T storage) where T : IViewModel, new()
    {
        if (storage != null)
            return storage;
        try
        {
            var json = Load(typeof(T).ToString());
            return storage = Deserialize<T>(json);
        }
        catch (Exception)
        {
            return new T();
        }
    }

    private static void Set<T>(ref T storage, T value) where T : IViewModel
    {
        if (storage?.Equals(value))
            return;
        try
        {
            var json = Serialize(value);
            Save(json, typeof(T).ToString());
        }
        catch (Exception)
        {
            Save(string.Empty, typeof(T).ToString());
        }
    }

    private static void Save(string value, string key)
    {
        throw new NotImplementedException();
    }

    private static string Serialize(object obj)
    {
        throw new NotImplementedException();
    }

    private static string Load(string key)
    {
        throw new NotImplementedException();
    }

    private static T Deserialize<T>(string obj)
    {
        throw new NotImplementedException();
    }
}

祝你好运! //杰瑞

答案 2 :(得分:0)

在Shoaib Shaikh获得一些灵感后,我决定建立一个全球存储库。请查看这个原因我几乎不知道我在做什么: - )。

我有三节课。所有类都使用DataContract,因此很容易序列化。第一个PersonViewModel非常简单:

[DataContract()]
public class PersonViewModel : BaseViewModel
{
    public PersonViewModel(string name)
    {
        Name = name;
    }

    #region Name property

    [DataMember()]
    private string _Name;

    public string Name
    {
        get
        {
            return _Name;
        }
        set
        {
            SetPropertyValue(ref _Name, value, () => Name);
        }
    }

    #endregion
}

其次是PersonListViewModel。每个PersonViewModel都存储在一个带有字符串id的全局哈希表中。本课程负责ID:s。通过调用RefreshPersonCollection,可以从全局对象重建人员列表。相当笨拙,最好是按要求接待这些人,但我现在太累了,无法解决这个问题: - )。

[DataContract()]
public class PersonListViewModel : BaseViewModel
{
    [DataMember()]
    private List<string> PersonIds = new List<string>();

    public PersonListViewModel()
    {
        Persons = new ObservableCollection<PersonViewModel>();

        CreateDefaultData();
    }

    public void CreateDefaultData()
    {
        for(int i=0; i<3; i++)
        {
            string personid = Guid.NewGuid().ToString();
            string personname = "Person " + personid;
            PersonViewModel person = new PersonViewModel(personname);

            PersonIds.Add(personid);
            Persons.Add(person);
            SharedObjects.Instance.Objects[personid] = person;
        }
    }

    public void RefreshPersonCollection()
    {
        Persons = new ObservableCollection<PersonViewModel>();

        foreach (string personid in PersonIds)
        {
            Persons.Add((PersonViewModel)SharedObjects.Instance.Objects[personid]);
        }
    }

    public ObservableCollection<PersonViewModel> Persons{ get; set; }
}

第三类是我的全局存储库。我想也很直截了当。所有PersonViewModels和所有PersonListViewModel都存储在此存储库中。

[DataContract()]
public class SharedObjects
{
    public static SharedObjects Instance;

    public SharedObjects()
    {
        Objects = new Dictionary<string, object>();
    }

    public void Init()
    {
        Objects["mainviewmodel"] = new PersonListViewModel();
    }

    [DataMember()]
    private Dictionary<string, Object> _Objects;

    public Dictionary<string, Object> Objects
    {
        get { return _Objects; }
        set { _Objects = value; }
    }
}

在我的Windows商店应用程序中,我有一个SuspensionManager,我稍微修改了它以序列化和反序列化我的全局存储库。

第一个更改是将我的新类型添加到要序列化的已知类型。我不喜欢这样,希望这些类能以某种方式自己完成(据我所知,这是可能的)。

static SuspensionManager()
{
         _knownTypes.Add(typeof(SharedObjects));
         _knownTypes.Add(typeof(PersonListViewModel));
         _knownTypes.Add(typeof(PersonViewModel));
}

SaveAsync中的第二个更改是确保保存全局数据。只添加了一行:

            //I added this:
            _sessionState["globalobjects"] = SharedObjects.Instance;

            // Serialize the session state synchronously to avoid asynchronous access to shared
            // state
            MemoryStream sessionData = new MemoryStream();
            DataContractSerializer serializer = new DataContractSerializer(typeof(Dictionary<string, object>), _knownTypes);
            serializer.WriteObject(sessionData, _sessionState);

第三次更改是在RestoreAsync中。

            // Get the input stream for the SessionState file
            StorageFile file = await ApplicationData.Current.LocalFolder.GetFileAsync(sessionStateFilename);
            using (IInputStream inStream = await file.OpenSequentialReadAsync())
            {
                // Deserialize the Session State
                DataContractSerializer serializer = new DataContractSerializer(typeof(Dictionary<string, object>), _knownTypes);
                _sessionState = (Dictionary<string, object>)serializer.ReadObject(inStream.AsStreamForRead());
            }

            //I added this:
            if (_sessionState.ContainsKey("globalobjects"))
                SharedObjects.Instance = (SharedObjects) _sessionState["globalobjects"];

这感觉很易于管理,但任何改进建议都值得赞赏:-)。这也适用于Windows Phone(SuspensionManager除外,但我想这个平台上的内容类似)?