-
-
Save gshackles/f20d5f444234c78ca81a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public abstract class SubViewModelBase<TResult> : ViewModelBase | |
{ | |
protected string MessageId { get; private set; } | |
protected SubViewModelBase(string messageId) | |
{ | |
MessageId = messageId; | |
} | |
protected void Cancel() | |
{ | |
ReturnResult(default(TResult)); | |
} | |
protected void ReturnResult(TResult result) | |
{ | |
var message = new SubNavigationResultMessage<TResult>(this, MessageId, result); | |
MessengerHub.Publish(message); | |
Close(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class SubViewModelTests : ViewModelTestsBase | |
{ | |
[Test] | |
public void RequestSubNavigate_NavigatesToChildViewModel_PassesInMessageId() | |
{ | |
var parentViewModel = new ParentViewModel(); | |
parentViewModel.GoToChildViewCommand.Execute(); | |
Assert.AreEqual(1, Dispatcher.NavigateRequests.Count); | |
var request = Dispatcher.NavigateRequests.First(); | |
Assert.That(request.ViewModelType == typeof(ChildViewModel)); | |
Assert.That(request.ParameterValues.ContainsKey("messageId")); | |
} | |
[Test] | |
public void RequestSubNavigate_ResultMessageReceived_ParentIsNotifiedAndUnsubscribes() | |
{ | |
var parentViewModel = new ParentViewModel(); | |
parentViewModel.GoToChildViewCommand.Execute(); | |
var messageId = Dispatcher.NavigateRequests.First().ParameterValues["messageId"]; | |
MessengerHub.Publish(new SubNavigationResultMessage<string>(this, messageId, "Result 1")); | |
Assert.AreEqual("Result 1", parentViewModel.LastResult); | |
MessengerHub.Publish(new SubNavigationResultMessage<string>(this, messageId, "Result 2")); | |
Assert.AreEqual("Result 1", parentViewModel.LastResult); | |
} | |
[Test] | |
public void ChildView_ReturnsResult_ParentIsNotifiedAndUnsubscribes() | |
{ | |
var parentViewModel = new ParentViewModel(); | |
parentViewModel.GoToChildViewCommand.Execute(); | |
var messageId = Dispatcher.NavigateRequests.First().ParameterValues["messageId"]; | |
var childViewModel = new ChildViewModel(messageId); | |
childViewModel.ReturnResult("Result 1"); | |
Assert.AreEqual("Result 1", parentViewModel.LastResult); | |
var secondChildViewModel = new ChildViewModel(messageId); | |
secondChildViewModel.ReturnResult("Result 2"); | |
Assert.AreEqual("Result 1", parentViewModel.LastResult); | |
} | |
public class ParentViewModel : ViewModelBase | |
{ | |
public string LastResult { get; private set; } | |
public IMvxCommand GoToChildViewCommand | |
{ | |
get { return new MvxRelayCommand(() => RequestSubNavigate<ChildViewModel, string>(null, onResult)); } | |
} | |
private void onResult(string result) | |
{ | |
LastResult = result; | |
} | |
} | |
public class ChildViewModel : SubViewModelBase<string> | |
{ | |
public ChildViewModel(string messageId) | |
: base(messageId) | |
{ | |
} | |
public new void ReturnResult(string result) | |
{ | |
base.ReturnResult(result); | |
} | |
public new void Cancel() | |
{ | |
base.Cancel(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public abstract class ViewModelBase | |
: MvxViewModel, | |
IMvxServiceConsumer<ITinyMessengerHub> | |
{ | |
protected ViewModelBase() | |
{ | |
MessengerHub = this.GetService<ITinyMessengerHub>(); | |
} | |
protected ITinyMessengerHub MessengerHub { get; private set; } | |
protected bool RequestSubNavigate<TViewModel, TResult>(IDictionary<string, string> parameterValues, Action<TResult> onResult) | |
where TViewModel : SubViewModelBase<TResult> | |
{ | |
parameterValues = parameterValues ?? new Dictionary<string, string>(); | |
if (parameterValues.ContainsKey("messageId")) | |
throw new ArgumentException("parameterValues cannot contain an item with the key 'messageId'"); | |
string messageId = Guid.NewGuid().ToString(); | |
parameterValues["messageId"] = messageId; | |
TinyMessageSubscriptionToken token = null; | |
token = MessengerHub.Subscribe<SubNavigationResultMessage<TResult>>(msg => | |
{ | |
if (token != null) | |
MessengerHub.Unsubscribe<SubNavigationResultMessage<TResult>>(token); | |
onResult(msg.Result); | |
}, | |
msg => msg.MessageId == messageId); | |
return RequestNavigate<TViewModel>(parameterValues); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
There is one problem I can see with this pattern right now.
The problem is in Tombstoning - so is an advanced scenario.
To illustrate the scenario:
There's a similar error flow in WP7 (but slightly different - as WP7's tombstoning is slightly different)
I'm sure this can be worked around with some persistence... or it could be ignored for 99% of apps.
The reason I'm so aware of tombstoning is because I ran into a problem with StartActivityForResult on Android - basically, starting a Camera activity on one test phone always caused tombstoning - which meant that state and event listeners were lost. It all got very confusing.