Hello,
I have two pages (a master and a detail page) that I want to show in my Xamarin.Forms app. The layout can be compared the UWP Mail app: The master page contains the list of all messages and the detail page shows one e-mail message. When the width of the app is small (e.g. phone), only one page is shown at a given time. When the users wants to read the email message (= visit the details page), the list of messages disappears and only the email message is shown (= navigates from master page to detail page). When the width of the app is sufficiently large (e.g. tablet in landscape mode), the list of email messages is shown on the left and the selected message is displayed on the right (= master and detail page are shown side by side).
How can I recreate such a behavior for my app? My master page is a list view from which I can navigate to the detail page, but I also want to show these two pages side by side when the app is wide enough.
My details "page" does not have to be a XAML page, I could also use e.g. ContentView if this is easier. However, thus far I was unable to create the layout I described.
Regards,
Philipp
I do it by having a Grid that has a variable number of columns, with cells that contain ContentViews that I set to hold the appropriate elements (title, toolbar, page content). I also maintain my own navigation stacks, so that I can push/pop pages in any column, move pages from one column to the other, and swap columns. I also support changing how much of the available width is given to each page. And I support having panels that span the overall width for those things that do not relate specifically to one of the contained pages.
What I do is possibly/probably more generic than you need. By the time the basic support for presenting multiple pages, toolbar support added for each page, a navigation system added, events received by the wrapper page being translated into events for the contained pages (e.g. when the width of the wrapper page changes), etc., it's a lot of work.
Answers
1. There will be two viewmodels for both the pages and one view model for combined page.
2. Use your combined viewmodel to show and hide your pages based on idiom of your device.
3. Same as viewmodel, there will be two pages for both and one page for combined behaviour.
4. Show pages based on the idiom of device.
@kingmathers
I do it by having a Grid that has a variable number of columns, with cells that contain ContentViews that I set to hold the appropriate elements (title, toolbar, page content). I also maintain my own navigation stacks, so that I can push/pop pages in any column, move pages from one column to the other, and swap columns. I also support changing how much of the available width is given to each page. And I support having panels that span the overall width for those things that do not relate specifically to one of the contained pages.
What I do is possibly/probably more generic than you need. By the time the basic support for presenting multiple pages, toolbar support added for each page, a navigation system added, events received by the wrapper page being translated into events for the contained pages (e.g. when the width of the wrapper page changes), etc., it's a lot of work.
@JohnHardman
That's sounds exactly like what I need. I had just hoped that some control would be available to make things easier. I know the UWP toolkit has a similar control which handles navigation etc. by itself which I used before (I am porting an existing UWP app to Xamarin.Forms).
I will be looking into your solution with the Grid. Why do you change the number of columns? My first idea would be to change the width of columns to hide to zero instead, but I have not yet started working on this.
You could do it without changing the number of columns, particularly if you ensure that the hidden column has no content. If you don't clear the content, you'll be using resources for things that the user cannot see, and there is the potential (on devices with physical keyboards) for tab index and shortcut/access keys to do unexpected things.
Ah of course that makes sense. I guess removing the columns completely is the better option.
@JohnHardman
I have gotten the UI to work more or less but how exactly do you manage the variable rows and the contents? Do you have a Grid and just bind the Content property to the ViewModel (in this case the ViewModel holds the ContentView) or do you have the ContentView finished in the XAML and just bind the values (texts, icons etc.) to the existing ContentView (in this case the ViewModel only holds Strings etc, not a ContentView or other XAML objects)?
Also where do you handle change in width? VisualStateManager, code behind or data binding?
The latter, although I use declarative C# rather than XAML.
I did my implementation before the VisualStateManager existed. I have it in code behind, effectively in the base class for the pages. In split screen mode, the base class does calculations to convert the width it is allocated into the widths for each contained page, then forwards on the width information to those contained pages.
@JohnHardman
Thanks again for your reply, this has been really helpful. I now have two XAML ContentViews which load into the Grid from code-behind, where I also change the number of columns and the width of the the columns of the Grid.
I am actually porting a UWP app where I used the MasterDetailsView from the UWP toolkit. This control allowed me to do just what I described and as such I am trying to recreate as much as I can of this control to reduce UI changes. This has been helpful because I know what I want to achieve but also difficult because I feel like I have little flexibility in the design.
Since you said that you have Title and Toolbar within your control, do you hide the NavigationBar on the containing page? How did you create the title/toolbar within the Contentview? Is there any control that handles the different operating system, especially the different back button on Android, UWP and iOS?
I don't currently hide the NavigationBar, although I may do so in future. I found that there were issues when it is hidden on UWP (I cannot remember the details though), so have kept the NavigationBar for the time being.
The Grid that contains the ContentViews has two rows at the top. The top row contains the title for each "page", and the second row contains the toolbar for each "page", the toolbar being something I construct myself.
I have my own back button in the toolbar for each "page", as well as handling the navigation bar's back button and the physical back button. The back button for each "page" operates on the navigation stack for whichever column the page is in. The navigation bar's back button and the physical back button go through a different bit of code that first works out which was the last "page" pushed onto either column's navigation stack, then does the back operation for that column.