切换视图时,从ViewModel保留UI状态

时间:2014-02-05 07:37:56

标签: wpf mvvm

我正在使用SimpleMVVM Toolkit。

我有一个带有多个按钮的视图(manage_view),这些按钮将导航(设置框架的源)到新视图(manage_import_view,manage_scanners_view等)。每个视图都有自己的VM。

对于每个视图,我使用定位器将datacontext设置为VM。定位器将ServiceAgent注入VM。

问题是当我导航到其他视图时,前一个视图的状态将丢失。例如,我在Manage_Import_View上执行导入并绑定到VM上的属性。当我导航到Manage_Scanners_View然后返回到Manage_Import_View时,我绑定的属性将丢失。

我明白发生了什么,但我不知道如何解决它。如何在它们之间切换时保持视图的状态?

期待您对此的看法。

(我已经搜索了Switching between views according to state,但这并不是我需要的。)

修改

我的定位器

public ImportViewModel ImportViewModel   
{  
    get  
    {  
        IIntegrationServiceAgent sa = new IntegrationServiceAgent();  
        return new ImportViewModel(sa);  
    }  
}  

在我看来的XAML中,我设置了datacontext

DataContext="{Binding Source={StaticResource Locator}, Path=ImportViewModel}"    

导航就是这样

private void Navigate(string pageName)  
{  
    Uri pageUri = new Uri("/Views/" + pageName + ".xaml", UriKind.Relative);  
    this.SelectedPage = pageUri;  
    this.SelectedPageName = pageName;  
}  

导入完成后,我有一个完成回调。这会设置我的视图所绑定的道具 - 这些是切换视图后重置的道具。

    private void ImportCompleted(IntegrationResult intresult, Exception error)
    {
        if (error == null)
        {
            _errorCount = intresult.Errors.Count;
            ErrorList = intresult.Errors;

            ResultMessage = intresult.Message;
            ErrorMessage = (errorList.Count == 1 ? "1 error" : errorList.Count.ToString() + " errors");
            Notify(ImportCompleteNotice, null);  // Tell the view we're done                
            ShowErrorDialog(importType);
        }
        else
            NotifyError(error.Message, error);

        IsImportBusy = false;
    }

2 个答案:

答案 0 :(得分:0)

这对我来说似乎很笨拙。我不完全确定为什么会发生这种情况,但我可以猜测......每次请求时都会从SelectedPage加载Uri,这将在每次加载时设置并解析XAML这会影响你的绑定。这就是我要做的事情:

首先在应用程序启动时,将所有视图加载到视图列表中

private Dictionary<string, Uri> viewUriDict;
private List<string> viewNameList = new List<string>() 
{
    "ViewA",
    "ViewB"
};

// The main View Model constructor.
public MainViewModel()
{
    viewUriDict = new Dictionary<string, Uri>();
    foreach (string s in viewNameList)
        viewUriDict.Add(s, new Uri("/Views/" + s + ".xaml", UriKind.Relative);
    this.SelectedPageName = viewNameList[0];
}

private string selectedPageName;
public string SelectedPageName
{
    get { return this.selectedPageName; }
    set
    {
        if (this.selectedPageName == value)
            return;
        this.selectedPageName = value;
        this.SelectedPage = this.viewUriDict[this.selectedPageName];
        OnPropertyChanged("SelectedPageName"); // For INotifyPropertyChanged.
    }
}

private Uri selectedPage;
private Uri selectedPageName
{
    get { return this.selectedPage; }
    set
    {
        if (this.selectedPage == value)
            return;
        this.selectedPage = value;
        OnPropertyChanged("SelectedPage"); // For INotifyPropertyChanged.
    }
}

现在,Uri列表缓存在您的主窗口/应用程序中。导航将成为

private void Navigate(string pageName)  
{  
    this.SelectedPageName = pageName;
}  

或仅设置this.SelectedPageName = "PageX"

我要做的第二件事是懒惰地实例化InportViewModel服务代理。我不确定如何调用它,但我不会在每次调用时重新创建服务代理...

private IIntegrationServiceAgent sa;
public ImportViewModel ImportViewModel   
{  
    get  
    {  
        if (sa == null)
            sa = new IntegrationServiceAgent();  
        return new ImportViewModel(sa);  
    }  
} 

这可能会解决您的问题,也可能不会。无论哪种方式,我希望它具有一定的价值。如果我是你,我会考虑使用Prism来做这类事情,尽管如果这是一个小项目可能会有点过分。

我希望这会有所帮助。

答案 1 :(得分:0)

对于经历过相同拼图的任何人,我都找到了答案herehere。 tonysneed在第二个链接上的回复解释了它。