Moved to a more simple navigation strategy, instead of MessagingCenter-based navigation.

This commit is contained in:
Joe Sauve 2016-01-21 21:57:22 -06:00
Родитель 373a095e1b
Коммит 7c3306e2df
9 изменённых файлов: 163 добавлений и 75 удалений

Просмотреть файл

@ -11,7 +11,7 @@ namespace Customers
SubscribeToDisplayAlertMessages();
SubscribeToNavigationMessages();
// SubscribeToNavigationMessages();
if (Device.OS == TargetPlatform.iOS)
navPage.BarTextColor = Color.White;
@ -53,15 +53,15 @@ namespace Customers
/// <summary>
/// Subscribes to messages for navigation.
/// </summary>
static void SubscribeToNavigationMessages()
{
MessagingService.Current.Subscribe(MessageKeys.PopAsync, async (service) =>
{
var task = Application.Current?.MainPage?.Navigation?.PopAsync();
if (task != null)
await task;
});
}
// static void SubscribeToNavigationMessages()
// {
// MessagingService.Current.Subscribe(MessageKeys.PopAsync, async (service) =>
// {
// var task = Application.Current?.MainPage?.Navigation?.PopAsync();
// if (task != null)
// await task;
// });
// }
}
}

Просмотреть файл

@ -6,9 +6,6 @@ namespace Customers
{
public const string DisplayAlert = "DisplayAlert";
public const string DisplayQuestion = "DisplayQuestion";
public const string NavigateToDetailPage = "NavigateToDetail";
public const string NavigateToEditPage = "NavigateToEdit";
public const string PopAsync = "PopAsync";
public const string SaveCustomer = "SaveCustomer";
public const string DeleteCustomer = "DeleteCustomer";
public const string CustomerLocationUpdated = "CustomerLocationUpdated";

Просмотреть файл

@ -57,6 +57,7 @@
<Compile Include="Data\ILocalization.cs" />
<Compile Include="Extensions\IntExtensions.cs" />
<Compile Include="Constants\MessageKeys.cs" />
<Compile Include="ViewModels\NavigationAwareBaseViewModel.cs" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<Import Project="..\packages\Xamarin.Forms.2.0.0.6490\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets" Condition="Exists('..\packages\Xamarin.Forms.2.0.0.6490\build\portable-win+net45+wp80+win81+wpa81+MonoAndroid10+MonoTouch10+Xamarin.iOS10\Xamarin.Forms.targets')" />

Просмотреть файл

@ -23,24 +23,12 @@ namespace Customers
{
base.OnAppearing();
// subscribe to NavigateToEditPage messages
MessagingService.Current.Subscribe<CustomerDetailViewModel>(MessageKeys.NavigateToEditPage, async (service, viewmodel) =>
await Navigation.PushAsync(new CustomerEditPage() { BindingContext = ViewModel }));
// Typically, is preferable to call into the viewmodel for OnAppearing() logic to be performed,
// but we're not doing that in this case because we need to interact with the Xamarin.Forms.Map property on this Page.
// In the future, the Map type and it's properties may get more binding support, so that the map setup can be omitted from code-behind.
await SetupMap();
}
protected override void OnDisappearing()
{
base.OnDisappearing();
// unsubscribe from NavigateToEditPage messages
MessagingService.Current.Unsubscribe<CustomerDetailViewModel>(MessageKeys.NavigateToEditPage);
}
/// <summary>
/// Sets up the map.
/// </summary>

Просмотреть файл

@ -18,6 +18,11 @@ namespace Customers
Title = null; // because iOS already displays the previous page's title with the back button, we don't want to display it twice.
}
/// <summary>
/// Ensures the state field has 2 characters at most.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The PropertyChangedEventArgs</param>
void StateEntry_PropertyChanged (object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Text")
@ -35,6 +40,11 @@ namespace Customers
}
}
/// <summary>
/// Ensures the zip code field has 5 characters at most.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The PropertyChangedEventArgs</param>
void PostalCode_PropertyChanged (object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Text")

Просмотреть файл

@ -22,18 +22,26 @@ namespace Customers
fab.Clicked = AndroidAddButtonClicked;
}
/// <summary>
/// The action to take when a list item is tapped.
/// </summary>
/// <param name="sender"> The sender.</param>
/// <param name="e">The ItemTappedEventArgs</param>
void ItemTapped (object sender, ItemTappedEventArgs e)
{
// send message to navigate to detail page
MessagingService.Current.SendMessage<CustomerDetailViewModel>(MessageKeys.NavigateToDetailPage, new CustomerDetailViewModel((Customer)e.Item));
Navigation.PushAsync(new CustomerDetailPage() { BindingContext = new CustomerDetailViewModel((Customer)e.Item) });
((ListView)sender).SelectedItem = null;
}
/// <summary>
/// The action to take when the + button is clicked on Android.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The EventArgs</param>
void AndroidAddButtonClicked (object sender, EventArgs e)
{
// send message to navigate to edit page (new customer)
MessagingService.Current.SendMessage(MessageKeys.NavigateToEditPage);
Navigation.PushAsync(new CustomerEditPage() { BindingContext = new CustomerDetailViewModel(new Customer()) });
}
protected override void OnAppearing()
@ -41,32 +49,6 @@ namespace Customers
base.OnAppearing();
ViewModel.LoadCustomersCommand.Execute(null);
// subscribe to messages to navigate to detail page
MessagingService.Current.Subscribe<CustomerDetailViewModel>(MessageKeys.NavigateToDetailPage, async (service, viewmodel) =>
await Navigation.PushAsync(new CustomerDetailPage() { BindingContext = viewmodel }));
// subscribe to messages to navigate to edit page (new customer)
MessagingService.Current.Subscribe(MessageKeys.NavigateToEditPage, async (service) =>
await Navigation.PushAsync(new CustomerEditPage() { BindingContext = new CustomerDetailViewModel(new Customer()) }));
// subscribe to messages to navigate to edit page (existing customer)
MessagingService.Current.Subscribe<CustomerDetailViewModel>(MessageKeys.NavigateToEditPage, async (service, viewmodel) =>
await Navigation.PushAsync(new CustomerEditPage() { BindingContext = viewmodel }));
}
protected override void OnDisappearing()
{
base.OnDisappearing();
// unsubscribe from messages to navigate to detail page
MessagingService.Current.Unsubscribe<CustomerDetailViewModel>(MessageKeys.NavigateToDetailPage);
// unsubscribe from messages to navigate to edit page (new customer)
MessagingService.Current.Unsubscribe(MessageKeys.NavigateToEditPage);
// unsubscribe from messages to navigate to edit page (existing customer)
MessagingService.Current.Unsubscribe<CustomerDetailViewModel>(MessageKeys.NavigateToEditPage);
}
}
}

Просмотреть файл

@ -11,7 +11,7 @@ using FormsToolkit;
namespace Customers
{
public class CustomerDetailViewModel : BaseViewModel
public class CustomerDetailViewModel : NavigationAwareBaseViewModel
{
bool _IsNewCustomer;
@ -78,11 +78,11 @@ namespace Customers
get
{
return _SaveCustomerCommand ??
(_SaveCustomerCommand = new Command(ExecuteSaveCustomerCommand));
(_SaveCustomerCommand = new Command(() => ExecuteSaveCustomerCommand()));
}
}
void ExecuteSaveCustomerCommand()
async Task ExecuteSaveCustomerCommand()
{
if (String.IsNullOrWhiteSpace(Customer.LastName) || String.IsNullOrWhiteSpace(Customer.FirstName))
{
@ -104,11 +104,9 @@ namespace Customers
}
else
{
// send a message that we want the given customer to be saved
MessagingService.Current.SendMessage<Customer>(MessageKeys.SaveCustomer, this.Customer);
// perform a pop in order to navigate back to the customer list
MessagingService.Current.SendMessage(MessageKeys.PopAsync);
await PopAsync();
}
}
@ -143,13 +141,13 @@ namespace Customers
get
{
return _EditCustomerCommand ??
(_EditCustomerCommand = new Command(ExecuteEditCustomerCommand));
(_EditCustomerCommand = new Command(async () => await ExecuteEditCustomerCommand()));
}
}
void ExecuteEditCustomerCommand()
async Task ExecuteEditCustomerCommand()
{
MessagingService.Current.SendMessage<CustomerDetailViewModel>(MessageKeys.NavigateToEditPage, this);
await PushAsync(new CustomerEditPage() { BindingContext = this });
}
@ -163,7 +161,7 @@ namespace Customers
get
{
return _DeleteCustomerCommand ??
(_DeleteCustomerCommand = new Command(ExecuteDeleteCustomerCommand));
(_DeleteCustomerCommand = new Command(ExecuteDeleteCustomerCommand));
}
}
@ -175,16 +173,16 @@ namespace Customers
Question = null,
Positive = "Delete",
Negative = "Cancel",
OnCompleted = new Action<bool>(result =>
OnCompleted = new Action<bool>(async result =>
{
if (result)
{
await PopAsync(false);
await PopAsync();
// send a message that we want the given customer to be deleted
MessagingService.Current.SendMessage<Customer>(MessageKeys.DeleteCustomer, this.Customer);
MessagingService.Current.SendMessage(MessageKeys.PopAsync);
MessagingService.Current.SendMessage(MessageKeys.PopAsync);
}
})
});

Просмотреть файл

@ -9,7 +9,7 @@ using FormsToolkit;
namespace Customers
{
public class CustomerListViewModel : BaseViewModel
public class CustomerListViewModel : NavigationAwareBaseViewModel
{
public CustomerListViewModel()
{
@ -98,14 +98,13 @@ namespace Customers
get
{
return _NewCustomerCommand ??
(_NewCustomerCommand = new Command(ExecuteNewCustomerCommand));
(_NewCustomerCommand = new Command(async () => await ExecuteNewCustomerCommand()));
}
}
void ExecuteNewCustomerCommand()
async Task ExecuteNewCustomerCommand()
{
// send message to navigate to edit page (new customer)
MessagingService.Current.SendMessage(MessageKeys.NavigateToEditPage, new CustomerDetailViewModel(new Customer()));
await PushAsync(new CustomerEditPage() { BindingContext = new CustomerDetailViewModel(new Customer()) });
}
Command _DialNumberCommand;

Просмотреть файл

@ -0,0 +1,113 @@
using System;
using MvvmHelpers;
using Xamarin.Forms;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace Customers
{
/// <summary>
/// Implements the INavigation interface on top of BaseViewModel.
/// </summary>
public abstract class NavigationAwareBaseViewModel : BaseViewModel, INavigation
{
readonly INavigation _Navigation;
protected NavigationAwareBaseViewModel()
{
// If Navigation is available on Application.Current.MainPage, get it.
_Navigation = Application.Current?.MainPage?.Navigation;
}
#region INavigation implementation
public void RemovePage(Page page)
{
_Navigation?.RemovePage(page);
}
public void InsertPageBefore(Page page, Page before)
{
_Navigation?.InsertPageBefore(page, before);
}
public async Task PushAsync(Page page)
{
var task = _Navigation?.PushAsync(page);
if (task != null)
await task;
}
public async Task<Page> PopAsync()
{
var task = _Navigation?.PopAsync();
return task != null ? await task : await Task.FromResult(null as Page);
}
public async Task PopToRootAsync()
{
var task = _Navigation?.PopToRootAsync();
if (task != null)
await task;
}
public async Task PushModalAsync(Page page)
{
var task = _Navigation?.PushModalAsync(page);
if (task != null)
await task;
}
public async Task<Page> PopModalAsync()
{
var task = _Navigation?.PopModalAsync();
return (task != null) ? await task : await Task.FromResult(null as Page);
}
public async Task PushAsync(Page page, bool animated)
{
var task = _Navigation?.PushAsync(page, animated);
if (task != null)
await task;
}
public async Task<Page> PopAsync(bool animated)
{
var task = _Navigation?.PopAsync(animated);
return (task != null) ? await task : await Task.FromResult(null as Page);
}
public async Task PopToRootAsync(bool animated)
{
var task = _Navigation?.PopToRootAsync(animated);
if (task != null)
await task;
}
public async Task PushModalAsync(Page page, bool animated)
{
var task = _Navigation?.PushModalAsync(page, animated);
if (task != null)
await task;
}
public async Task<Page> PopModalAsync(bool animated)
{
var task = _Navigation?.PopModalAsync(animated);
return (task != null) ? await task : await Task.FromResult(null as Page);
}
public IReadOnlyList<Page> NavigationStack
{
get { return _Navigation?.NavigationStack; }
}
public IReadOnlyList<Page> ModalStack
{
get { return _Navigation?.ModalStack; }
}
#endregion
}
}