How to implement custom navigation service in mvvm

2019-06-17 18:51发布

I am not quite comfortable with the existing MVVMlight navigation interface methods and that is very minimal and I want to implement my very own navigational interface in which I can expose sophisticated methods that manipulates the navigational stack and integrate it with the MVVM light.

Any guidance on achieving this is very much appreciated

Update:

I would like to implement other transitions for movement between pages like page curl,flip,rotate etc

1条回答
Viruses.
2楼-- · 2019-06-17 19:31

Here's a full implementation example that would solve the problem by adding a new interface that fully replaces the one from MvvmLight and also allows you to choose whether to use animations or not. In this example, we add the ability to control whether the navigation should be animated or not:

Interface

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);
}

Implementation

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;
    }

}

From here, you can add other methods you would like. Make sure to inject this or use it directly where you were using your MvvmLight one before.

查看更多
登录 后发表回答