Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement DialogView for Uap #3074

Merged
merged 20 commits into from
Oct 3, 2018
Merged

Implement DialogView for Uap #3074

merged 20 commits into from
Oct 3, 2018

Conversation

andres-gimenez
Copy link
Contributor

✨ What kind of change does this PR introduce? (Bug fix, feature, docs update...)

New feature. Implement ModalView for Uap

I haven't been able to prove it well, because the Playground.Uwp project doesn't start.

⤵️ What is the current behavior?

🆕 What is the new behavior (if this is a feature change)?

💥 Does this PR introduce a breaking change?

🐛 Recommendations for testing

📝 Links to relevant issues/docs

🤔 Checklist before submitting

@martijn00
Copy link
Contributor

@nickrandolph can you have a look at why the playground doesn't start?

@@ -23,6 +23,9 @@ public class MvxWindowsViewPresenter
{
protected readonly IMvxWindowsFrame _rootFrame;

private MvxWindowsContentDialog mDialogView;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we avoid by any chance holding a strong reference to the dialog view here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know how to do it. You have access to the ViewModel, but not to the View.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't follow the naming conventions we use.

@andres-gimenez
Copy link
Contributor Author

To run the Playground, throw this exception. I don't now if this error is reported.

MvvmCross.Exceptions.MvxException
HResult=0x80131500
Message=Problem navigating to ViewModel RootViewModel
Source=MvvmCross
StackTrace:
at MvvmCross.ViewModels.MvxAppStart`1.d__1.MoveNext() in D:\Apl\Xamarin\MvvmCross\MvvmCross\MvvmCross\ViewModels\MvxAppStart.cs:line 83
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at MvvmCross.ViewModels.MvxAppStart.d__5.MoveNext() in D:\Apl\Xamarin\MvvmCross\MvvmCross\MvvmCross\ViewModels\MvxAppStart.cs:line 43
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at MvvmCross.ViewModels.MvxAppStart.Start(Object hint) in D:\Apl\Xamarin\MvvmCross\MvvmCross\MvvmCross\ViewModels\MvxAppStart.cs:line 28
at MvvmCross.Platforms.Uap.Views.MvxApplication.RunAppStart(IActivatedEventArgs activationArgs) in D:\Apl\Xamarin\MvvmCross\MvvmCross\MvvmCross\Platforms\Uap\Views\MvxApplication.cs:line 72
at MvvmCross.Platforms.Uap.Views.MvxApplication.OnLaunched(LaunchActivatedEventArgs activationArgs) in D:\Apl\Xamarin\MvvmCross\MvvmCross\MvvmCross\Platforms\Uap\Views\MvxApplication.cs:line 46

Inner Exception 1:
MvxException: Failed to construct and initialize ViewModel for type Playground.Core.ViewModels.RootViewModel from locator MvxDefaultViewModelLocator - check InnerException for more information

Inner Exception 2:
MvxException: Problem running viewModel lifecycle of type RootViewModel

Inner Exception 3:
NullReferenceException: Object reference not set to an instance of an object.

@@ -23,6 +23,9 @@ public class MvxWindowsViewPresenter
{
protected readonly IMvxWindowsFrame _rootFrame;

private MvxWindowsContentDialog mDialogView;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't follow the naming conventions we use.

try
{
var modalAttribute = (MvxModalViewPresentationAttribute)attribute;
var instanceReques = (MvxViewModelInstanceRequest)request;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this cast closer to usage. Also typo.

{
get
{
return _viewModel;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please use Expression body

{
public new TViewModel ViewModel
{
get { return (TViewModel)base.ViewModel; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expression body

@martijn00 martijn00 dismissed Cheesebaron’s stale review August 22, 2018 07:40

Changes are implemented

@@ -240,5 +250,39 @@ protected virtual Task<bool> ShowPage(Type viewType, MvxBasePresentationAttribut
return Task.FromResult(false);
}
}

protected virtual async Task<bool> ShowModal(Type viewType, MvxBasePresentationAttribute attribute, MvxViewModelRequest request)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should you pass in MvxModalViewPresentationAttribute as type?

{
if (Activator.CreateInstance(viewType) is MvxWindowsContentDialog modalView)
{
var instanceReques = (MvxViewModelInstanceRequest)request;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo

@@ -23,6 +23,8 @@ public class MvxWindowsViewPresenter
{
protected readonly IMvxWindowsFrame _rootFrame;

private MvxWindowsContentDialog _windowsContentDialog;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it is good to keep an instance reference like this. We probably need something to find the view back in the stack.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made.


protected virtual Task<bool> CloseModal(IMvxViewModel viewModel, MvxBasePresentationAttribute attribute)
{
_windowsContentDialog?.Hide();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is Hide correct, or do we really need to remove it as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's the right one. PrimaryButtonCommand can be invoked, but it's rare.


namespace MvvmCross.Platforms.Uap.Presenters.Attributes
{
public sealed class MvxModalViewPresentationAttribute : MvxBasePresentationAttribute
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't make it sealed

@andres-gimenez andres-gimenez requested a review from a team August 22, 2018 15:56
typeof(MvxModalViewPresentationAttribute),
new MvxPresentationAttributeAction
{
ShowAction = (view, attribute, request) => ShowModal(view, (MvxModalViewPresentationAttribute)attribute, (MvxViewModelInstanceRequest)request),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should not cast to MvxViewModelInstanceRequest here, but in the method

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not understand why attribute yes and request no. What criterion do you have?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{
try
{
if (Activator.CreateInstance(viewType) is MvxWindowsContentDialog modalView)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't there a view creator for Windows? @nickrandolph

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ContentDialog is created with the new command. But if you know another way to do it, propose it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This way viewmodel events like prepare and Initialize are not triggered. If there is nothing for this on Windows yet we need to make it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ContentDialog not is a page. I can create a method to create the ContentDialog. I can't think of anything else.


protected virtual Task<bool> CloseModal(IMvxViewModel viewModel, MvxBasePresentationAttribute attribute)
{
var popups = VisualTreeHelper.GetOpenPopups(Window.Current).FirstOrDefault(p => p.Child is ContentDialog);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check for MvxWindowsContentDialog to get a closer match. If possible also check the viewmodel type or something to make sure we don't close the wrong one when multiple modals are open.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You cannot open two ContentDialog at a time.

typeof(MvxModalViewPresentationAttribute),
new MvxPresentationAttributeAction
{
ShowAction = (view, attribute, request) => ShowModal(view, (MvxModalViewPresentationAttribute)attribute, (MvxViewModelInstanceRequest)request),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{
try
{
if (Activator.CreateInstance(viewType) is MvxWindowsContentDialog modalView)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This way viewmodel events like prepare and Initialize are not triggered. If there is nothing for this on Windows yet we need to make it.

{
if (Activator.CreateInstance(viewType) is MvxWindowsContentDialog modalView)
{
modalView.ViewModel = request.ViewModelInstance;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, you should not set the instance manually. It should be done from a helper or something.

@@ -256,14 +256,15 @@ protected virtual async Task<bool> ShowModal(Type viewType, MvxModalViewPresenta
{
try
{
if (Activator.CreateInstance(viewType) is MvxWindowsContentDialog modalView)
IMvxWindowsContentDialog contentDialog;
if ((contentDialog = CreateContentDialog(attribute, viewType)) != null)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please split assignment and null check

@andres-gimenez
Copy link
Contributor Author

I changed the modal name to dialog. A ContentDialog is not a modal window. And it can confuse.

@andres-gimenez andres-gimenez changed the title Implement ModalView for Uap Implement DialogView for Uap Aug 29, 2018
@andres-gimenez
Copy link
Contributor Author

This is a sample for can use x:Bind in XAML.

@andres-gimenez
Copy link
Contributor Author

Is there anything left to do? Codefactor's warnings are for putting two classes in the same file.

@nickrandolph
Copy link
Contributor

Apologies been unavailable to contribute. A quick glance - I think in the close method we should be confirming that the open dialogue is for the viewmodel being closed

@andres-gimenez
Copy link
Contributor Author

If it leaves you calmer. Here's the modification. But you can only open one ContentDialog per window.

I'm trying to be able to open Standalone windows. And if you can open two ContentDialog. But they are placed in different visual trees. When you closed this change I send the window modal. I need help because you have to modify MvxWindowsMainThreadDispatcher.

Cheesebaron
Cheesebaron previously approved these changes Sep 11, 2018
@MvvmCross MvvmCross deleted a comment from Cheesebaron Oct 2, 2018
@martijn00 martijn00 added this to the 6.2.1 milestone Oct 2, 2018
@martijn00 martijn00 dismissed their stale review October 2, 2018 13:03

Implemented changes

@martijn00
Copy link
Contributor

@andrechi1 @nickrandolph @Cheesebaron i've done a rebase and implemented the changes to get this merged in.

@martijn00 martijn00 merged commit 58fa58c into MvvmCross:develop Oct 3, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

5 participants