MVVM with Master Detail Pages

HuntJasonHuntJason Jason HuntUSMember

Hello,
In a windows native application I was able to use DataTemplates and MVVM to switch between content pages. I have been scouring for a similar solution for Xamarin.Forms to have the NavPage of the Master Detail behave similarly but have been unsuccessful in figuring this out. Any assistance is greatly appreciated.

From my WPF native windows application:

View:

    <Window ...>
     <Window.Resources>
        <ResourceDictionary>
            <DataTemplate DataType="{x:type viewmodel:MonthlyViewModel}">
                 <view:MonthlyControl/>
            </DataTemplate>
            <DataTemplate DataType="{x:type viewmodel:WeeklyViewModel}">
                 <view:WeeklyControl/>
            </DataTemplate>
        </ResourceDictionary>
    </Window.Resources>
    <StackPanel>
        <Border>
            <ContentControl Content="{Binding SelectedSchedule}" />
        </Border>
        ...
    </StackPanel>
    ...
  </Window>

ViewModel:

        public class MyWindowViewModel {
                IScheduleStrategy currentSchedule;

                public MyWindowViewModel() {
                        CurrentSchedule = new MonthlyViewModel();
                }

                public ListItemViewModel<IScheduleStrategy> CurrentSchedule { 
                    get { return currentSchedule; }
                    set { SetProperty(ref currentSchedule, value); }
               }
        }

Best Answer

Answers

  • JohnMillerJohnMiller John Miller USForum Administrator, Xamarin Team Xamurai
    edited April 2016

    @HuntJason,

    You may want to take a look at ControlTemplates. Jason posted about this on his blog, here.

    There is also another great post here.

    Another technique I have used is to make my own custom view that can swap it's content out based on a DataTemplate, using a DataTemplateSelector. Something like this:

    // TemplatedGrid.xaml
    <Grid 
        xmlns="http://xamarin.com/schemas/2014/forms" 
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
        x:Class="Controls.TemplatedGrid">
    
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
    
        <Grid x:Name="ContentGrid" Grid.Row="0" />
    
    </Grid>
    
    // TemplatedGrid.xaml.cs
    public partial class TemplatedGrid : Grid
        {
            public TemplatedGrid()
            {
                InitializeComponent();
            }
    
            public static readonly BindableProperty ContentTemplateSelectorProperty =
                BindableProperty.Create(nameof(ContentTemplateSelector), typeof(Utility.DataTemplateSelector), typeof(TemplatedGrid), default(Utility.DataTemplateSelector));
    
            public DataTemplateSelector ContentTemplateSelector
            {
                get { return (Utility.DataTemplateSelector)GetValue(ContentTemplateSelectorProperty); }
                set { SetValue(ContentTemplateSelectorProperty, value); }
            }
    
            protected override void OnBindingContextChanged()
            {
                base.OnBindingContextChanged();
    
                if(BindingContext != null)
                    SetContent();
            }
    
            void SetContent()
            {
                ContentGrid.Children.Clear();
    
                var template = ContentTemplateSelector.SelectTemplate(BindingContext, this);
                var view = template.CreateContent() as View;
                view.BindingContext = BindingContext;
    
                ContentGrid.Children.Add(view);
            }
        }
    

    Then, you can use it like this:

    // "controls" is just my xmlns definition for the namespace of this custom control
    <controls:TemplatedGrid 
        BindingContext="{Binding SomeContext}"
        ContentTemplateSelector="{StaticResource TemplateSelector}"/>
    
    // Resources
    <util:CustomTemplateSelector x:Key="TemplateSelector"/>
    

    util:CustomTemplateSelector is an instance of DataTemplateSelector, exampled here.

  • HuntJasonHuntJason Jason Hunt USMember

    After reading more about the Hamburger Menu pattern and why to avoid it, I changed from wanting to use the MasterDetailPage and switched to the TabbedPage as my main form of navigation within my application. I was also able to accomplish the desired MVVM pattern by modifying the TabbedPage thanks to help from the BindablePicker example here in the forums.

  • Matthew.4307Matthew.4307 Matthew USMember ✭✭✭

    In my app I use Messaging Center to request a change of the detail. It's the easier clean way I found.

  • HuntJasonHuntJason Jason Hunt USMember

    One problem with using the Messaging Center is that, because it's a singleton, it's not as easily testable.

  • Matthew.4307Matthew.4307 Matthew USMember ✭✭✭

    Messaging Center does have it's downsides, especially if you forget to Unsubscribe ;). It's still a great feature with a lot of flexibility that I'm not sure many people are aware of it's existence.

  • HuntJasonHuntJason Jason Hunt USMember

    It is great, but I suspect that utilizing it as a mechanism to change/add details is somewhat of a golden hammer.

  • abraabra Abra Sat ADMember ✭✭

    @JohnMiller : could you please post a link to the complete solution for swapping the content of the custom view, using a DataTemplateSelector ?

Sign In or Register to comment.