I need to add a side drawer to an app that has a Xamarin Forms TabbedPage as it's main page - I am aiming for the same navigation as e.g. the Twitter app on Android.
However the MainContent property of the RadSideDrawer is of type View instead of Page so I cannot set it to a TabbedPage instance.
-> Is it possible to use a TabbedPage with RadSideDrawer? If yes, how?
If this is not possible, would the standard Xamarin Forms MasterDetailPage, offer an alternative?
It has Master and Detail properties of type Page and it is used to create a side drawer in e.g. the Hanselman.Forms app (although not on a TabbedPage).
7 Answers, 1 is accepted

PS When I create a single header instance and return that each time in the GroupHeaderTemplate (see code below), the header looks OK but I still wonder whether this invoke twice behaviour is by design or a bug?
var header = new Label { HorizontalTextAlignment = TextAlignment.Center, Text = "Welcome to Xamarin Forms!" };
GroupHeaderTemplate = new DataTemplate(() => {
return header; // This is called twice instead of once so do not create new view instances here
});

Pls ignore my above reply; it belongs to another question
I would still like to see my question on SideDrawer answered!
One possible approach here would be to place RadSideDrawer within a page and use it as Master in a MasterDetailPage and use a TabbedPage as Detail. Alternatively, you can use only TabbedPage, but you will need to place one RadSideDrawer control within every child page.
Best regards,
Ves
Telerik by Progress

Hi,
Can you provide some sample code to implement the possible way that you described.
Thank you,
I'm assuming you mean this part of Vesselin's response?
"place RadSideDrawer within a page and use it as Master in a MasterDetailPage and use a TabbedPage as Detail"
Demo
Start with the Xamarin Master Detail Page template:

Put the RadSideDrawer in the MasterPage
<
ContentPage
...
x:Class
=
"MasterDetailPlacement.Portable.Views.MasterDetailPage1Master"
Title
=
"Master"
>
<
primitives:RadSideDrawer
x:Name
=
"drawer"
DrawerLength
=
"200"
>
<
primitives:RadSideDrawer.DrawerContent
>
<
ListView
ItemsSource
=
"{Binding MenuItems}"
>
</
ListView
>
</
primitives:RadSideDrawer.DrawerContent
>
</
primitives:RadSideDrawer
>
</
ContentPage
>
DetailPage
<
TabbedPage
xmlns
=
"http://xamarin.com/schemas/2014/forms"
x:Class
=
"MasterDetailPlacement.Portable.Views.MasterDetailPage1Detail"
Title
=
"Detail"
>
<!--Pages can be added as references or inline-->
<
ContentPage
Title
=
"Tab 1"
/>
<
ContentPage
Title
=
"Tab 2"
/>
<
ContentPage
Title
=
"Tab 3"
/>
</
TabbedPage
>
and here's the MasterDetail root:
<
MasterDetailPage
xmlns
=
"http://xamarin.com/schemas/2014/forms"
x:Class
=
"MasterDetailPlacement.Portable.Views.MasterDetailPage1"
xmlns:pages
=
"clr-namespace:MasterDetailPlacement.Portable.Views"
>
<
MasterDetailPage.Master
>
<
pages:MasterDetailPage1Master
x:Name
=
"MasterPage"
/>
</
MasterDetailPage.Master
>
<
MasterDetailPage.Detail
>
<
NavigationPage
>
<
x:Arguments
>
<
pages:MasterDetailPage1Detail
/>
</
x:Arguments
>
</
NavigationPage
>
</
MasterDetailPage.Detail
>
</
MasterDetailPage
>
Finally, you'll of course have to wire up the navigation a little differently because the Master Detail template uses a NavigationPage instead of a Tabbed page, but that's trivial. Here is the documentaiton on how to use a TabbedPage, there is also a full demo here.
In a nutshell, you can get the index of the selected item from the ListView in the SideDrawer and then use that index to select the item on the TabbedPage
public
partial
class
MasterDetailPage1 : MasterDetailPage
{
public
MasterDetailPage1()
{
InitializeComponent();
MasterPage.ListView.ItemSelected += ListView_ItemSelected;
}
private
void
ListView_ItemSelected(
object
sender, SelectedItemChangedEventArgs e)
{
// UPDATED for use with TabbedPage as Detail
if
(e.SelectedItem
is
MasterDetailPage1MenuItem item)
{
// get the index of the selected item
var vm = MasterPage.BindingContext
as
MasterDetailPage1Master.MasterDetailPage1MasterViewModel;
var index = vm?.MenuItems.IndexOf(item);
if
(index ==
null
)
return
;
if
((Detail
as
NavigationPage)?.CurrentPage
is
TabbedPage tabbedPage)
{
tabbedPage.SelectedItem = tabbedPage.Children[(
int
)index];
}
IsPresented =
false
;
MasterPage.ListView.SelectedItem =
null
;
}
}
}
Summary
Ultimately, the RadSideDrawer was not designed for Page navigation as the SideDrawer's MainContent is of type View, and does not work for content of type Page. The above approach may cause more problems than just using the MasterPage as is (with just a ListView/RadListView).
For an alternate solution to Page navigation, take a look at our Tagit example for inspiration.
Regards,
Lance | Tech Support Engineer, Sr.
Progress Telerik

I found a solution that doesn't need to use MasterDetailPage:
By having a global Drawer in Holder.SideDrawer as this line, you don't need to define it on every tabbedPage or contentPage:
public static RadSideDrawer SideDrawer { get; set; }
This is the Xaml code for the toolbar item in the tabbed pages:
<TabbedPage.ToolbarItems>
<ToolbarItem x:Name="SideMenuToolbarItem" Priority="1" Order="Primary" Icon="sideMenuIcon.png" Clicked="SideMenuToolbarItem_OnClicked" />
</TabbedPage.ToolbarItems>
In the Tabbed pages these two methods should be written:
private void SideMenuToolbarItem_OnClicked(object sender, EventArgs e)
{
CurrentPage = Helper.SideBarMenuItemOnClicked((ContentPage)CurrentPage);
}
protected override void OnCurrentPageChanged()
{
base.OnCurrentPageChanged();
if (Holder.SideDrawer != null)
{
Holder.SideDrawer.IsOpen = false;
Holder.SideDrawer = null;
}
}
By making the Holder.SideDrawer null, we make sure it won't left open when switching tabs.
This is the definition of Helper.SideBarMenuItemOnClicked:
public static Page SideBarMenuItemOnClicked(ContentPage page)
{
if (Holder.SideDrawer != null && Holder.SideDrawer.IsOpen)
{
Holder.SideDrawer.IsOpen = false;
return page;
}
page.Content = SideBarMenuItemOnClicked(page.Content);
return page;
}
public static View SideBarMenuItemOnClicked(View content)
{
if (Holder.SideDrawer != null && Holder.SideDrawer.IsOpen)
{
Holder.SideDrawer.IsOpen = false;
return content;
}
var drawerContent = new SideBarMenuView(content);
Holder.SideDrawer = new RadSideDrawer
{
MainContent = content,
DrawerContent = drawerContent,
DrawerLength = 250,
DrawerLocation = SideDrawerLocation.Right,
DrawerTransitionType = SideDrawerTransitionType.SlideInOnTop,
IsOpen = true
};
content = Holder.SideDrawer;
return content;
}
The last method can also be used for normal content pages.
Finally, it's up to you to define SideBarMenuView however you need:
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class SideBarMenuView : ContentView
{
public SideBarMenuView(View content)
{
InitializeComponent();
}
}
Good luck.
