Kurumsal Uygulama Gezintisi

Not

Bu e-Kitap 2017 baharında yayımlanmıştır ve o zamandan beri güncelleştirilmemiştir. Kitapta değerli kalan çok şey var, ancak bazı malzemeler güncelliğini yitirmiş.

Xamarin.Forms , genellikle kullanıcının kullanıcı arabirimiyle etkileşiminden veya iç mantık temelli durum değişikliklerinin bir sonucu olarak uygulamanın kendisinden kaynaklanan sayfa gezintisi desteği içerir. Ancak, aşağıdaki zorlukların karşılanması gerektiğinden, gezintinin Model-View-ViewModel (MVVM) desenini kullanan uygulamalarda uygulanması karmaşık olabilir:

  • Görünümler arasında sıkı bağlama ve bağımlılıklar içermeyen bir yaklaşım kullanarak, gidilecek görünümü tanımlama.
  • Gidilecek görünümün örneği oluşturulup başlatıldığı işlemi koordine etme. MVVM kullanılırken görünüm ve görünüm modelinin örneği oluşturulup görünümün bağlama bağlamı aracılığıyla birbiriyle ilişkilendirilmesi gerekir. Bir uygulama bağımlılık ekleme kapsayıcısı kullanırken görünümlerin ve görünüm modellerinin örneğini oluşturmak için belirli bir yapı mekanizması gerekebilir.
  • İlk görüntüleme gezintisi mi yoksa model öncelikli gezintiyi mi görüntüleyebileceğiniz. Görünüm öncelikli gezintide, gidecek sayfa görünüm türünün adına başvurur. Gezinti sırasında, belirtilen görünüme karşılık gelen görünüm modeli ve diğer bağımlı hizmetlerle birlikte örnek oluşturulur. Alternatif bir yaklaşım, model öncesini görüntüleme gezintisini kullanmaktır; burada gidileceği sayfa, görünüm modeli türünün adına başvurur.
  • Uygulamanın gezinti davranışını görünümler arasında temiz bir şekilde ayırma ve modelleri görüntüleme. MVVM düzeni, uygulamanın kullanıcı arabirimiyle sunusu ve iş mantığı arasında bir ayrım sağlar. Ancak, bir uygulamanın gezinti davranışı genellikle kullanıcı arabirimine ve uygulamanın sunu bölümlerine yayılır. Kullanıcı genellikle bir görünümden gezinti başlatır ve gezintinin bir sonucu olarak görünüm değiştirilir. Ancak, gezintinin genellikle görünüm modeli içinden başlatılması veya koordine edilmesi gerekebilir.
  • Başlatma amacıyla gezinti sırasında parametreleri geçirme. Örneğin, kullanıcı sipariş ayrıntılarını güncelleştirmek için bir görünüme giderse, doğru verileri görüntüleyebilmesi için sipariş verilerinin görünüme geçirilmesi gerekir.
  • Belirli iş kurallarına uyulmasını sağlamak için gezintiyi koordine etme. Örneğin, kullanıcılardan bir görünümden ayrılmadan önce, geçersiz verileri düzeltebilmeleri veya görünümde yapılan veri değişikliklerini göndermeleri veya atmaları istenmesi istenebilir.

Bu bölüm, model öncelikli sayfa gezintisini görüntülemek için kullanılan bir NavigationService sınıf sunarak bu zorlukları ele alır.

Not

NavigationService Uygulama tarafından kullanılan, yalnızca ContentPage örnekleri arasında hiyerarşik gezinti gerçekleştirmek için tasarlanmıştır. Hizmeti kullanarak diğer sayfa türleri arasında gezinmek beklenmeyen davranışlara neden olabilir.

Gezinti mantığı, bir görünümün arka planında veya veriye bağlı görünüm modelinde bulunabilir. Gezinti mantığını bir görünüme yerleştirmek en basit yaklaşım olsa da, birim testleri aracılığıyla kolayca test edilemez. Görünüm modeli sınıflarında gezinti mantığı yerleştirmek, mantığın birim testleri aracılığıyla kullanılabilmesi anlamına gelir. Ayrıca görünüm modeli, belirli iş kurallarının uygulandığından emin olmak için gezintiyi denetlemek için mantık uygulayabilir. Örneğin bir uygulama, girilen verilerin geçerli olduğundan emin olmadan kullanıcının sayfadan uzaklaşmasına izin vermeyebilir.

Test NavigationService edilebilirliği artırmak için genellikle görünüm modellerinden bir sınıf çağrılır. Ancak görünüm modellerinden görünümlere gitmek için görünüm modellerinin görünümlere ve özellikle etkin görünüm modelinin ilişkilendirilmediği görünümlere başvurması gerekir ve bu önerilmez. Bu nedenle, NavigationService burada sunulan görünüm modeli türünü gidecek hedef olarak belirtir.

eShopOnContainers mobil uygulaması, model öncelikli görüntüleme gezintisi NavigationService sağlamak için sınıfını kullanır. Bu sınıf, aşağıdaki kod örneğinde gösterilen arabirimini uygular INavigationService :

public interface INavigationService  
{  
    ViewModelBase PreviousPageViewModel { get; }  
    Task InitializeAsync();  
    Task NavigateToAsync<TViewModel>() where TViewModel : ViewModelBase;  
    Task NavigateToAsync<TViewModel>(object parameter) where TViewModel : ViewModelBase;  
    Task RemoveLastFromBackStackAsync();  
    Task RemoveBackStackAsync();  
}

Bu arabirim, uygulayan bir sınıfın aşağıdaki yöntemleri sağlaması gerektiğini belirtir:

Yöntem Purpose
InitializeAsync Uygulama başlatıldığında iki sayfadan birine gezinti gerçekleştirir.
NavigateToAsync Belirtilen sayfaya hiyerarşik gezinti gerçekleştirir.
NavigateToAsync(parameter) Bir parametre geçirerek belirtilen bir sayfaya hiyerarşik gezinti gerçekleştirir.
RemoveLastFromBackStackAsync Önceki sayfayı gezinti yığınından kaldırır.
RemoveBackStackAsync Önceki sayfaların tümünü gezinti yığınından kaldırır.

Ayrıca, INavigationService arabirim uygulayan bir sınıfın bir PreviousPageViewModel özellik sağlaması gerektiğini belirtir. Bu özellik, gezinti yığınındaki önceki sayfayla ilişkili görünüm modeli türünü döndürür.

Not

Bir INavigationService arabirim genellikle gezinti yığınındaki önceki sayfaya program aracılığıyla dönmek için kullanılan bir GoBackAsync yöntem de belirtir. Ancak gerekli olmadığından eShopOnContainers mobil uygulamasında bu yöntem eksik.

NavigationService Örneği Oluşturma

NavigationService Arabirimini uygulayan INavigationService sınıfı, aşağıdaki kod örneğinde gösterildiği gibi Autofac bağımlılık ekleme kapsayıcısı ile tekil olarak kaydedilir:

builder.RegisterType<NavigationService>().As<INavigationService>().SingleInstance();

Arabirim INavigationService , aşağıdaki kod örneğinde ViewModelBase gösterildiği gibi sınıf oluşturucusunda çözümlenir:

NavigationService = ViewModelLocator.Resolve<INavigationService>();

Bu, sınıfındaki NavigationService yöntemi tarafından oluşturulan Autofac bağımlılık ekleme kapsayıcısında depolanan nesneye InitNavigation App bir başvuru döndürür. Daha fazla bilgi için bkz . Uygulama Başlatıldığında Gezinme.

ViewModelBase sınıfı örneği türünde INavigationServicebir NavigationService özellikte depolarNavigationService. Bu nedenle, sınıfından ViewModelBase türetilen tüm görünüm modeli sınıfları, arabirimi tarafından INavigationService belirtilen yöntemlere erişmek için özelliğini kullanabilirNavigationService. Bu, autofac bağımlılık ekleme kapsayıcısından nesneyi her görünüm modeli sınıfına ekleme yükünü NavigationService önler.

Gezinti İsteklerini İşleme

Xamarin.Forms , kullanıcının sayfalarda NavigationPage , ileri ve gerilerde istediği gibi gezinebileceği hiyerarşik bir gezinti deneyimi uygulayan sınıfını sağlar. Hiyerarşik gezinti hakkında daha fazla bilgi için bkz . Hiyerarşik Gezinti.

eShopOnContainers uygulaması, sınıfı doğrudan kullanmak NavigationPage yerine aşağıdaki kod örneğinde CustomNavigationView gösterildiği gibi sınıfını sınıfta sarmalarNavigationPage:

public partial class CustomNavigationView : NavigationPage  
{  
    public CustomNavigationView() : base()  
    {  
        InitializeComponent();  
    }  

    public CustomNavigationView(Page root) : base(root)  
    {  
        InitializeComponent();  
    }  
}

Bu sarmalamanın amacı, sınıfı için XAML dosyasının NavigationPage içindeki örneği şekillendirmeyi kolaylaştırmaktır.

Gezinti, aşağıdaki kod örneğinde gösterildiği gibi yöntemlerden biri NavigateToAsync çağrılarak, gidilmekte olan sayfanın görünüm modeli türü belirtilerek görünüm modeli sınıflarının içinde gerçekleştirilir:

await NavigationService.NavigateToAsync<MainViewModel>();

Aşağıdaki kod örneği, sınıfı tarafından NavigationService sağlanan yöntemleri gösterirNavigateToAsync:

public Task NavigateToAsync<TViewModel>() where TViewModel : ViewModelBase  
{  
    return InternalNavigateToAsync(typeof(TViewModel), null);  
}  

public Task NavigateToAsync<TViewModel>(object parameter) where TViewModel : ViewModelBase  
{  
    return InternalNavigateToAsync(typeof(TViewModel), parameter);  
}

Her yöntem, sınıfından ViewModelBase türetilen herhangi bir görünüm modeli sınıfının yöntemini çağırarak hiyerarşik gezinti gerçekleştirmesine InternalNavigateToAsync olanak tanır. Buna ek olarak, ikinci NavigateToAsync yöntem gezinti verilerinin genellikle başlatma gerçekleştirmek için kullanıldığı görünüm modeline geçirilen bir bağımsız değişken olarak belirtilmesine olanak tanır. Daha fazla bilgi için bkz . Gezinti Sırasında Parametreleri Geçirme.

InternalNavigateToAsync yöntemi gezinti isteğini yürütür ve aşağıdaki kod örneğinde gösterilir:

private async Task InternalNavigateToAsync(Type viewModelType, object parameter)  
{  
    Page page = CreatePage(viewModelType, parameter);  

    if (page is LoginView)  
    {  
        Application.Current.MainPage = new CustomNavigationView(page);  
    }  
    else  
    {  
        var navigationPage = Application.Current.MainPage as CustomNavigationView;  
        if (navigationPage != null)  
        {  
            await navigationPage.PushAsync(page);  
        }  
        else  
        {  
            Application.Current.MainPage = new CustomNavigationView(page);  
        }  
    }  

    await (page.BindingContext as ViewModelBase).InitializeAsync(parameter);  
}  

private Type GetPageTypeForViewModel(Type viewModelType)  
{  
    var viewName = viewModelType.FullName.Replace("Model", string.Empty);  
    var viewModelAssemblyName = viewModelType.GetTypeInfo().Assembly.FullName;  
    var viewAssemblyName = string.Format(  
                CultureInfo.InvariantCulture, "{0}, {1}", viewName, viewModelAssemblyName);  
    var viewType = Type.GetType(viewAssemblyName);  
    return viewType;  
}  

private Page CreatePage(Type viewModelType, object parameter)  
{  
    Type pageType = GetPageTypeForViewModel(viewModelType);  
    if (pageType == null)  
    {  
        throw new Exception($"Cannot locate page type for {viewModelType}");  
    }  

    Page page = Activator.CreateInstance(pageType) as Page;  
    return page;  
}

yöntemi, InternalNavigateToAsync önce yöntemini çağırarak görünüm modeline CreatePage gezinti gerçekleştirir. Bu yöntem, belirtilen görünüm modeli türüne karşılık gelen görünümü bulur ve bu görünüm türünün bir örneğini oluşturur ve döndürür. Görünüm modeli türüne karşılık gelen görünümü bulmak için kural tabanlı bir yaklaşım kullanılır ve bu yaklaşım şunları varsayar:

  • Görünümler, görünüm modeli türleriyle aynı derlemededir.
  • Görünümler bir içindedir. Alt ad alanını görüntüler.
  • Görünüm modelleri bir içindedir. ViewModels alt ad alanı.
  • Görünüm adları, "Model" kaldırılmış şekilde model adlarını görüntülemeye karşılık gelir.

Bir görünümün örneği oluşturulurken ilgili görünüm modeliyle ilişkilendirilir. Bunun nasıl gerçekleştiği hakkında daha fazla bilgi için bkz . Görünüm Modeli Bulucu ile Otomatik Olarak Görünüm Modeli Oluşturma.

Oluşturulan görünüm bir LoginViewise, sınıfın yeni bir örneğine CustomNavigationView sarmalanır ve özelliğine Application.Current.MainPage atanır. Aksi takdirde, CustomNavigationView örnek alınır ve null değilse, PushAsync oluşturulan görünümü gezinti yığınına göndermek için yöntemi çağrılır. Ancak, alınan CustomNavigationView örnek ise null, oluşturulan görünüm sınıfın CustomNavigationView yeni bir örneğinde sarmalanır ve özelliğine Application.Current.MainPage atanır. Bu mekanizma, gezinti sırasında sayfaların hem boş olduğunda hem de veri içerdiğinde gezinti yığınına doğru şekilde eklenmesini sağlar.

İpucu

Sayfaları önbelleğe almayı göz önünde bulundurun. Sayfa önbelleğe alma, şu anda görüntülenmeyen görünümler için bellek tüketimine neden olur. Ancak, sayfa önbelleğe alınmadan, XAML ayrıştırma ve sayfanın yapısı ile görünüm modelinin her yeni sayfaya gidildiğinde gerçekleşeceği ve bu da karmaşık bir sayfa için performans etkisi yaratabileceği anlamına gelir. Aşırı sayıda denetim kullanmayan iyi tasarlanmış bir sayfa için performans yeterli olmalıdır. Ancak sayfa önbelleğe alma işlemi, yavaş sayfa yükleme süreleri ile karşılaşıldığında yardımcı olabilir.

Görünüm oluşturulduktan ve konumuna gidildikten sonra, InitializeAsync görünümün ilişkili görünüm modelinin yöntemi yürütülür. Daha fazla bilgi için bkz . Gezinti Sırasında Parametreleri Geçirme.

Uygulama başlatıldığında, sınıfındaki InitNavigation App yöntemi çağrılır. Aşağıdaki kod örneği bu yöntemi gösterir:

private Task InitNavigation()  
{  
    var navigationService = ViewModelLocator.Resolve<INavigationService>();  
    return navigationService.InitializeAsync();  
}

yöntemi, Autofac bağımlılık ekleme kapsayıcısında yeni NavigationService bir nesne oluşturur ve yöntemini çağırmadan InitializeAsync önce buna bir başvuru döndürür.

Not

INavigationService Arabirim sınıfı tarafından ViewModelBase çözümlendiğinde kapsayıcı, InitNavigation yöntemi çağrıldığında oluşturulan nesneye bir başvuru NavigationService döndürür.

Aşağıdaki kod örneği yöntemini gösterir NavigationService InitializeAsync :

public Task InitializeAsync()  
{  
    if (string.IsNullOrEmpty(Settings.AuthAccessToken))  
        return NavigateToAsync<LoginViewModel>();  
    else  
        return NavigateToAsync<MainViewModel>();  
}

MainView, uygulamanın kimlik doğrulaması için kullanılan önbelleğe alınmış bir erişim belirteci varsa adresine gider. Aksi takdirde, LoginView öğesine gider.

Autofac bağımlılık ekleme kapsayıcısı hakkında daha fazla bilgi için bkz . Bağımlılık Eklemeye Giriş.

Gezinti Sırasında Parametreleri Geçirme

NavigateToAsync Arabirim tarafından belirtilen yöntemlerden biri, gezinti verilerinin INavigationService genellikle başlatma gerçekleştirmek için kullanıldığı görünüm modeline geçirilen bir bağımsız değişken olarak belirtilmesine olanak tanır.

Örneğin, sınıfı, ProfileViewModel kullanıcı sayfadan bir OrderDetailCommand sipariş ProfileView seçtiğinde yürütülen bir içerir. Bu da aşağıdaki kod örneğinde gösterilen yöntemini yürütür OrderDetailAsync :

private async Task OrderDetailAsync(Order order)  
{  
    await NavigationService.NavigateToAsync<OrderDetailViewModel>(order);  
}

Bu yöntem, kullanıcının sayfada seçtiği sırayı OrderDetailViewModeltemsil eden bir Order örnek geçirerek öğesine gezintiyi ProfileView çağırır. NavigationService sınıfı öğesini oluşturduğundaOrderDetailViewOrderDetailViewModel, sınıf örneği oluşturulur ve görünümün BindingContextöğesine atanır. yöntemi, öğesine gittikten OrderDetailViewInternalNavigateToAsync sonra görünümün ilişkili görünüm modelinin yöntemini yürütürInitializeAsync.

InitializeAsync yöntemi, sınıfında geçersiz kılınabilecek bir yöntem olarak tanımlanırViewModelBase. Bu yöntem, object gezinti işlemi sırasında görünüm modeline geçirilecek verileri temsil eden bir bağımsız değişken belirtir. Bu nedenle, bir gezinti işleminden veri almak isteyen model sınıflarını görüntüleme, gerekli başlatmayı gerçekleştirmek için yönteminin kendi uygulamasını InitializeAsync sağlar. Aşağıdaki kod örneği sınıfından InitializeAsync yöntemini OrderDetailViewModel gösterir:

public override async Task InitializeAsync(object navigationData)  
{  
    if (navigationData is Order)  
    {  
        ...  
        Order = await _ordersService.GetOrderAsync(  
                        Convert.ToInt32(order.OrderNumber), authToken);  
        ...  
    }  
}

Bu yöntem, gezinti işlemi sırasında görünüm modeline geçirilen örneği alır Order ve örnekten tam sipariş ayrıntılarını OrderService almak için kullanır.

Davranışlar Kullanarak Gezintiyi Çağırma

Gezinti genellikle bir kullanıcı etkileşimi tarafından bir görünümden tetikler. Örneğin, başarılı kimlik doğrulamasından LoginView sonra gezinti gerçekleştirir. Aşağıdaki kod örneği, gezintinin bir davranış tarafından nasıl çağrıldığı gösterir:

<WebView ...>  
    <WebView.Behaviors>  
        <behaviors:EventToCommandBehavior  
            EventName="Navigating"  
            EventArgsConverter="{StaticResource WebNavigatingEventArgsConverter}"  
            Command="{Binding NavigateCommand}" />  
    </WebView.Behaviors>  
</WebView>

çalışma zamanında ile EventToCommandBehavior etkileşime WebViewyanıt verir. WebView bir web sayfasına gittiği zaman, Navigating olay tetiklenir ve içinde yürütülür NavigateCommand LoginViewModel. Varsayılan olarak, olayın olay bağımsız değişkenleri komutuna geçirilir. Bu veriler, özelliğinde EventArgsConverter belirtilen dönüştürücü tarafından kaynak ve hedef arasında geçirildikçe dönüştürülür ve bu da dosyasından WebNavigatingEventArgsdeğerini Url döndürür. Bu nedenle, yürütülürken NavigationCommand , web sayfasının Url'si kayıtlı Actionöğesine parametre olarak geçirilir.

Buna karşılık, NavigationCommand aşağıdaki kod örneğinde gösterilen yöntemi yürütülür NavigateAsync :

private async Task NavigateAsync(string url)  
{  
    ...          
    await NavigationService.NavigateToAsync<MainViewModel>();  
    await NavigationService.RemoveLastFromBackStackAsync();  
    ...  
}

Bu yöntem , gezintisini MainViewModelçağırır ve aşağıdaki gezinti, sayfayı LoginView gezinti yığınından kaldırır.

Gezintiyi Onaylama veya İptal Etme

Kullanıcının gezintiyi onay edebilmesi veya iptal edebilmesi için bir uygulamanın gezinti işlemi sırasında kullanıcıyla etkileşim kurması gerekebilir. Örneğin, kullanıcı bir veri giriş sayfasını tam olarak tamamlamadan önce gezinmeyi denediğinde bu gerekli olabilir. Bu durumda, bir uygulama kullanıcının sayfadan uzaklaşmasına veya gezinti işlemini gerçekleşmeden önce iptal etmesine olanak tanıyan bir bildirim sağlamalıdır. Bu, gezintinin çağrılıp çağrılmayacağını denetlemek için bir bildirimden gelen yanıt kullanılarak bir görünüm modeli sınıfında elde edilebilir.

Özet

Xamarin.Forms , genellikle kullanıcının kullanıcı arabirimiyle etkileşiminden veya iç mantık temelli durum değişikliklerinin bir sonucu olarak uygulamanın kendisinden kaynaklanan sayfa gezintisi desteği içerir. Ancak, gezintinin MVVM desenini kullanan uygulamalarda uygulanması karmaşık olabilir.

Bu bölümde, görünüm modellerinden model öncelikli görüntüleme gezintisi gerçekleştirmek için kullanılan bir NavigationService sınıf sunulmuştur. Görünüm modeli sınıflarında gezinti mantığı yerleştirmek, mantığın otomatikleştirilmiş testler aracılığıyla kullanılabilmesi anlamına gelir. Ayrıca görünüm modeli, belirli iş kurallarının uygulandığından emin olmak için gezintiyi denetlemek için mantık uygulayabilir.