导航到新页面会删除backstack

时间:2014-08-10 23:11:01

标签: c# windows mvvm windows-phone windows-phone-8.1

我有一个奇怪的反复出现的问题。有时它会消失,有时它会回来。我无法确定所有问题,我的所有断点似乎都按预期顺序命中。

当我导航到新页面时,我的后台堆栈一直被删除,因此只需按下应用程序的背景。显然这是一个问题。

我认为这可能是我更复杂的页面和视图模型结构的结果。我为Pages强制所有的NavigationHelper创建了一个新类,强制所有的Pages都是新类的子类。我强制说我的所有页面都附加到一个基本的PageViewModel类来解决两者之间的通信(我有一个更好的方法,但Xaml不能很好地运行),我使用NavigationService导航,我调用CurrentFrame,这是一个return Windows.Current.Content as Frame的静态方法。

以下是我认为的相关代码。有任何想法吗?提前感谢一堆。我不知道发生了什么:/

我使用NavigationService中的Navigate方法(而不是其他两个lolol)向前导航,但我的后退按钮无法正常返回。


public abstract class BaseViewModelPage : Page
{
    protected readonly NavigationHelper NavigationHelper;

    protected BaseViewModelPage()
    {
        NavigationHelper = new NavigationHelper(this);
        NavigationHelper.LoadState += navigationHelper_LoadState;
        NavigationHelper.SaveState += navigationHelper_SaveState;

        this.NavigationCacheMode = NavigationCacheMode.Required;
    }

    protected BasePageViewModel CurrentPageViewModel
    {
        get { return DataContext as BasePageViewModel; }
    }

    #region Navigation Registration

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        NavigationHelper.OnNavigatedTo(e);
    }

    protected override void OnNavigatedFrom(NavigationEventArgs e)
    {
        NavigationHelper.OnNavigatedFrom(e);
    }

    protected virtual void LoadState(LoadStateEventArgs e)
    {
        if (CurrentPageViewModel != null)
        {
            CurrentPageViewModel.LoadState(e);
        }
    }

    protected virtual void SaveState(SaveStateEventArgs e)
    {
        if (CurrentPageViewModel != null)
        {
            CurrentPageViewModel.SaveState(e);
        }
    }

    private void navigationHelper_LoadState(object sender, LoadStateEventArgs e)
    {
        LoadState(e);
    }

    private void navigationHelper_SaveState(object sender, SaveStateEventArgs e)
    {
        SaveState(e);
    }

    #endregion
}

public abstract class BasePageViewModel : ViewModelBase
{
    private bool _isLoading = false;
    public bool IsLoading
    {
        get
        {
            return _isLoading;
        }

        set
        {
            if (_isLoading == value)
            {
                return;
            }

            _isLoading = value;
            RaisePropertyChanged();
        }
    }

    public virtual void LoadState(LoadStateEventArgs e)
    {

    }

    public virtual void SaveState(SaveStateEventArgs e)
    {

    }
}

public class NavigationService : INavigationService
{
    public static readonly Dictionary<Type, Type> PageDictionary;

    static NavigationService()
    {
        PageDictionary = new Dictionary<Type, Type>();
        PageDictionary.Add(typeof(LogInPageViewModel), typeof(LogInPage));
        PageDictionary.Add(typeof(RegisterUserPageViewModel), typeof(RegisterUserPage));
    }

    public bool Navigate(Type pageViewModelType, Object parameter = null)
    {
        if (PageDictionary.ContainsKey(pageViewModelType))
        {
            if (parameter != null)
            {
                return App.CurrentFrame.Navigate(PageDictionary[pageViewModelType], parameter);
            }
            else
            {
                return App.CurrentFrame.Navigate(PageDictionary[pageViewModelType]);
            }
        }

        return false;
    }

    public bool GoBack()
    {
        if (CanGoBack())
        {
            App.CurrentFrame.GoBack();
        }

        return false;
    }

    public bool CanGoBack()
    {
        return App.CurrentFrame.CanGoBack;
    }

    public bool NavigateAndRemoveSelf(Type pageViewModelType, object parameter = null)
    {
        if (Navigate(pageViewModelType, parameter))
        {
            if (App.CurrentFrame.CanGoBack)
            {
                App.CurrentFrame.BackStack.RemoveAt(App.CurrentFrame.BackStackDepth - 1);
                return true;
            }
        }

        return false;
    }

    public bool NavigateAndRemoveAll(Type pageViewModelType, object parameter = null)
    {

        if (Navigate(pageViewModelType, parameter))
        {
            while (App.CurrentFrame.CanGoBack)
            {
                App.CurrentFrame.BackStack.RemoveAt(App.CurrentFrame.BackStackDepth - 1);
            }

            return true;
        }

        return false;
    }
}

更新[已解决]:

错误是由使用通用应用类库引起的。

我想将NavigationHelper.cs类(在WP8应用程序中默认生成)分离到库中。这样我就可以直接对VM进行单元测试(我无法使用Unit Test项目引用WP8应用程序)。因此,我将NavigationHelper.cs类以及上面的所有相关代码放在一个新的通用应用程序类库中。

NavigationHelper类依赖于两个东西,即BUILD中的WINDOWS_PHONE_APP宏,它影响NavigationHelper类中的特定部分,即HardwareButton BackPressed侦听器。

#if WINDOWS_PHONE_APP
            Windows.Phone.UI.Input.HardwareButtons.BackPressed += HardwareButtons_BackPressed;
#else

第二次依赖Windows.Phone大会。程序集存在于WP8应用程序中,但不适用于通用应用程序类库。这意味着即使我将WINDOWS_PHONE_APP宏添加到库中,该应用程序也无法编译。您不能在通用应用程序类库中使用Windows Phone 8 / 8.1项目生成的NavigationHelper。我会尝试提出这个问题。谢谢!

2 个答案:

答案 0 :(得分:1)

更新[已解决]:

错误是由使用通用应用类库引起的。

我想将NavigationHelper.cs类(在WP8应用程序中默认生成)分离到库中。这样我就可以直接对VM进行单元测试(我无法使用Unit Test项目引用WP8应用程序)。因此,我将NavigationHelper.cs类以及上面的所有相关代码放在一个新的通用应用程序类库中。

NavigationHelper类依赖于两个东西,即BUILD中的WINDOWS_PHONE_APP宏,它影响NavigationHelper类中的特定部分,即HardwareButton BackPressed侦听器。

#if WINDOWS_PHONE_APP
            Windows.Phone.UI.Input.HardwareButtons.BackPressed += HardwareButtons_BackPressed;
#else
    ...
#endif

由于未定义MACRO,后退按钮实际上不会返回。

第二个问题是缺少Windows.Phone程序集。程序集存在于WP8应用程序中,但不适用于通用应用程序类库。这意味着即使我向库中添加了WINDOWS_PHONE_APP宏,该应用程序也无法编译。您不能在通用应用程序类库中使用Windows Phone 8 / 8.1项目生成的NavigationHelper。我会尝试提出这个问题。谢谢!

答案 1 :(得分:0)

您可以将NavigationHelper保留在共享项目中,只需将其添加到Windows Phone项目中的MainPage即可。

 static MainPage()
        {
            HardwareButtons.BackPressed += (sender, args) =>
            {
                var frame = Window.Current.Content as Frame;
                if (frame != null && frame.CanGoBack)
                {
                    frame.GoBack();
                    args.Handled = true;
                }
            };
        }

这解决了我的BackButton问题。