如何在mvvmlight中实现自定义导航服务

7
我对现有的MVVMlight导航界面方法并不太满意,因为它非常简单,所以我想实现自己的导航界面,可以公开操纵导航堆栈的复杂方法,并将其与MVVM Light集成。
如果有关于如何实现这一点的指导,将不胜感激。
更新:
我希望实现其他页面之间的转场效果,例如翻页、翻转、旋转等。

1
你是怎么意思 将它与MVVM light集成?你可以创建自己的 ICustomNavigationService 接口,为不同的操作系统实现它,然后在 SimpleIoc 容器中注册实现。如果你对不同平台上的导航方式不太熟悉,可以在这里查看源代码 https://mvvmlight.codeplex.com/SourceControl/latest ,看看 MVVM light 的作者是如何实现的。 - Florian Moser
感谢您对此提供的解释!基本上,我有一个应用程序,它已经使用了共享代码中的INavigationService,它被iOS、Android和Windows应用程序使用。现在,我只想用自己的服务替换iNavigation服务,该服务将提供访问导航堆栈的额外API。如果可能的话,如何实现? - Sharath
1
你需要创建一个新的接口,我们称之为 ISharathNavigationService,并定义所有必要的操作。你可以在共享代码中使用这个接口。然后,在每个平台上实现它(例如 WindowsNavigationService),并使用 SimpleIoc 容器将其注册到接口中(例如 SimpleIoc.Default.Register<ISharathNavigationService, WindowsNavigationService>())。最后,在共享代码中,你可以调用 SimpleIoc 容器来获取 ISharathNavigationService 的实例(类似于 SimpleIoc.Default.GetInstance<ISharathNavigationService>())。 - Florian Moser
谢谢!基本上我想创建一个接口,我可以通过方法访问自己的导航栈,并提供对底层导航栈的访问。如果您能向我解释如何做到这一点,我将非常感激!展示一个例子或模型会非常好。 - Sharath
1
你能具体说一下吗?你卡在哪里了?我知道这需要一些工作;我会通过查看mvvm light的源代码来理解“专家”是如何进行导航的,然后尝试通过添加我额外需要的内容来自己实现它。我相信已经有很好的资源可以教你如何修改iOS和Android的导航栈。 - Florian Moser
显示剩余5条评论
1个回答

6
这里是一个完整的实现示例,通过添加一个新的接口来完全替换MvvmLight中的接口,并允许您选择是否使用动画来解决问题。在这个示例中,我们添加了控制导航是否应该有动画的功能: 接口
public interface ICustomNavigationService
{
    string CurrentPageKey { get; }
    void GoBack(bool animate = true);
    void NavigateTo(string pageKey, bool animate = true);
    void NavigateTo(string pageKey, object parameter, bool animate = true);
}

实施

public class NavigationService : ICustomNavigationService
{
    private readonly Dictionary<string, Type> _pagesByKey = new Dictionary<string, Type>();
    private NavigationPage _navigation;
    public NavigationPage Navigation
    {
        get
        {
            return _navigation;
        }
    }
    public string CurrentPageKey
    {
        get
        {
            lock (_pagesByKey)
            {
                if (_navigation.CurrentPage == null)
                {
                    return null;
                }

                var pageType = _navigation.CurrentPage.GetType();

                return _pagesByKey.ContainsValue(pageType)
                    ? _pagesByKey.First(p => p.Value == pageType).Key
                    : null;
            }
        }
    }

    public void GoBack(bool animate = true)
    {
        _navigation.PopAsync(animate);
        MessagingCenter.Send<INavigationService>(this, "NAVIGATING");
    }

    public void NavigateTo(string pageKey, bool animate = true)
    {
        NavigateTo(pageKey, null, animate);
        MessagingCenter.Send<INavigationService>(this, "NAVIGATING");
    }

    public void NavigateTo(string pageKey, object parameter, bool animate = true)
    {
        lock (_pagesByKey)
        {
            if (_pagesByKey.ContainsKey(pageKey))
            {
                var type = _pagesByKey[pageKey];
                ConstructorInfo constructor;
                object[] parameters;

                if (parameter == null)
                {
                    constructor = type.GetTypeInfo()
                        .DeclaredConstructors
                        .FirstOrDefault(c => !c.GetParameters().Any());

                    parameters = new object[]
                    {
                    };
                }
                else
                {
                    constructor = type.GetTypeInfo()
                        .DeclaredConstructors
                        .FirstOrDefault(
                            c =>
                            {
                                var p = c.GetParameters();
                                return p.Count() == 1
                                       && p[0].ParameterType == parameter.GetType();
                            });

                    parameters = new[]
                    {
                        parameter
                    };
                }

                if (constructor == null)
                {
                    throw new InvalidOperationException(
                        "No suitable constructor found for page " + pageKey);
                }

                var page = constructor.Invoke(parameters) as Page;
                _navigation.PushAsync(page, animate);
            }
            else
            {
                throw new ArgumentException(
                    string.Format(
                        "No such page: {0}. Did you forget to call NavigationService.Configure?",
                        pageKey),
                    "pageKey");
            }
        }
    }

    public void Configure(string pageKey, Type pageType)
    {
        lock (_pagesByKey)
        {
            if (_pagesByKey.ContainsKey(pageKey))
            {
                _pagesByKey[pageKey] = pageType;
            }
            else
            {
                _pagesByKey.Add(pageKey, pageType);
            }
        }
    }

    public void Initialize(NavigationPage navigation)
    {
        _navigation = navigation;
    }

}

从这里开始,您可以添加其他方法。确保注入此方法或直接在您之前使用的 MvvmLight 中使用它。


1
如何为弹出添加推送转换?或者在推入和弹出过程中如何进行其他类型的转换,例如翻转旋转页面翻卷 - Sharath
那是一个完全不同的问题。这个例子只是一个例子而已。它使用了 Xamarin.Forms 导航,这个导航没有为过渡提供额外的动画效果,你需要在 NavigationRenderer 中自定义实现。这个例子的重点是展示如何创建一个自定义接口的自定义实现,并将其用于 MvvmLight 的 NavigationService。如果您想要特殊的动画效果,您需要自己编写或从其他问题中提出分离的问题。 - SuavePirate
你是说在MVVM中我们可以进行推送和弹出而不需要转换动画,而在原生平台中可以应用转换动画...我不明白如何做到这一点。以Xamarin.iOS为例...导航发生在视图模型中,但我如何能够从本地端应用转换动画...请解释一下。 - Sharath
2
请记住,stackoverflow不是编程服务。从您的问题评论和这个示例中,您现在应该可以尝试自己解决这个问题。 - Florian Moser
1
Xamarin在此处提供了iOS导航转换的演示:https://developer.xamarin.com/samples/monotouch/TransitionsDemo/如果您遵循他们的模式,可以将其用作自定义导航服务中的实现。 - SuavePirate
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接