I am implementing the Navigation Drawer
on my project. I am following this blog for this feature.
Mainpage.xsml.cs:
public partial class NavigationDrawerPage : MasterDetailPage { public List<MasterPageItem> menuList { get; set; } public MainPage() { InitializeComponent(); menuList = new List<MasterPageItem>(); // Adding menu items to menuList and you can define title ,page and icon menuList.Add(new MasterPageItem() { Title = "Home", Icon = "home.png", TargetType = typeof(HomePage) }); menuList.Add(new MasterPageItem() { Title = "Setting", Icon = "setting.png", TargetType = typeof(SettingPage) }); menuList.Add(new MasterPageItem() { Title = "LogOut", Icon = "logout.png", TargetType = typeof(LogoutPage) }); navigationDrawerList.ItemsSource = menuList; Detail = new NavigationPage((Page)Activator.CreateInstance(typeof(HomePage))); } }
Mainpage.xaml
<StackLayout Grid.Row="1" Spacing="15"> <ListView x:Name="navigationDrawerList" RowHeight="60" SeparatorVisibility="None" BackgroundColor="#e8e8e8" ItemSelected="OnMenuItemSelected"> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <StackLayout> <!-- Main design for our menu items --> <StackLayout VerticalOptions="FillAndExpand" Orientation="Horizontal" Padding="20,10,0,10" Spacing="20"> <Image Source="{Binding Icon}" WidthRequest="30" HeightRequest="30" VerticalOptions="Center" /> <Label Text="{Binding Title}" FontSize="Medium" VerticalOptions="Center" TextColor="Black"/> </StackLayout> <BoxView HeightRequest="1" BackgroundColor="Gray"/> </StackLayout> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView> </StackLayout>
MasterPageItem.cs
public class MasterPageItem { public string Title { get; set; } public string Icon { get; set; } public Type TargetType { get; set; } }
My problem is when adding my content pages to list. The above code working perfect:
menuList.Add(new MasterPageItem() { Title = "Home", Icon = "home.png", TargetType = typeof(SettingPage) });
But I have a page having one argument, I can't add the argument inside of the TargetType
. See the below code:
menuList.Add(new MasterPageItem() { Title = "Help", Icon = "help.png", TargetType = typeof(HelpPage(false)) }); //showing syntax errors for this line
How can I add a content page having arguments into the list item? Should I change the TargetType
datatype
?
You could pass parameters with the method public static object CreateInstance(Type type, params object[] args);
public class MasterPageItem { public string Title { get; set; } public string Icon { get; set; } public Type TargetType { get; set; } public object[] args { get; set; } // }
menuList.Add(new MasterPageItem() { Title = "Home", Icon = "home.png", TargetType = typeof(HomePage), args = new object[] {"string", 1 , false} } ); // pass parameters whatever you want
public HomePage() //remain the default constructor { InitializeComponent(); } public HomePage (string s , int i , bool b) //add this { InitializeComponent (); }
Have you remained the Default constructor with MyTabbedPage
?
Check if the following method in MyTabbedPage.cs
public MyTabbedPage() { InitializeComponent(); }
No better way , you could hard code here
Detail = new NavigationPage((Page)Activator.CreateInstance(typeof(HomePage), new object[] { "string", 1, false }));
If you only need bool
value , just pass one parameter.
Detail = new NavigationPage((Page)Activator.CreateInstance(typeof(Homepage), new object[] { false }));
And change the constructor with only one parameter
public HomePage (bool b) //add this { InitializeComponent (); }
If you call the first one , it always hits the default constructor (without argument).
If you call the second one , it hits the constructor with arguments (it is determined by the parameters passed in the MasterPageItem)
Change the code in item selected event
private void OnMenuItemSelected(object sender, SelectedItemChangedEventArgs e) { var item = (MasterPageItem)e.SelectedItem; Type page = item.TargetType; Detail = new NavigationPage((Page)Activator.CreateInstance(page,item.args)); //this line IsPresented = false; }
If
menuList.Add(new MasterPageItem() { Title = "Announcements", Icon = "ic_topics_fill_xx.png", TargetType = typeof(HomePage), args = new object[] { "bool", 1, false } });
it hits
public HomePage (string s , int i , bool b) { InitializeComponent (); }
If
menuList.Add(new MasterPageItem() { Title = "Announcements", Icon = "ic_topics_fill_xx.png", TargetType = typeof(HomePage), args = new object[] { false } });
it hits
public HomePage ( bool b) { InitializeComponent (); }
If
menuList.Add(new MasterPageItem() { Title = "Announcements", Icon = "ic_topics_fill_xx.png", TargetType = typeof(HomePage)});
it hits
public HomePage () //default constructor { InitializeComponent (); }
Is it clear ?
.............
It should be Detail = new NavigationPage((Page)Activator.CreateInstance(page,item.args));
Answers
Personally I'd put those traits on the ViewModel for the pages.
Then you don't need the extra class of
MasterPageItem
. Just use the ViewModels as your collection.And your other classes aren't responsible for creating items and setting the properties. IE: Why would your
NavigationDrawer
be responsible for setting the titles and icons of _other_pages? It shouldn't know or control these things.@ClintStLaurent Can you share sample codes?
You could pass parameters with the method
public static object CreateInstance(Type type, params object[] args);
Item
MasterDetailPage
Add the constructor with corresponding parameters
My test
Hi @ColeX tried like above, my argument is a bool variable. but getting following Exception.
Have you remained the Default constructor with
MyTabbedPage
?Check if the following method in MyTabbedPage.cs
Samples of... ? Ya lost me. Sample of a property called "Title"? I don't understand what it is you want a sample of. If its just a matter of understanding MVVM, base classes for view models etc. you can hit up my tutorials.
http://redpillxamarin.com/2018/03/12/2018-101-vs2017-new-solution/
@ColeX It is working. One last question.
For the initial navigation, I am using the above code. So the same argument needs to pass here also, how can I do that here?
No better way , you could hard code here
@ColeX Why passing "string"?
{ "string", 1, false }));
Actually it is a bool variable, so can I pass like below?If you only need
bool
value , just pass one parameter.And change the constructor with only one parameter
Eeeek, I'd be rejecting that pull request
Prism makes these scenarios really simple.
https://prismlibrary.github.io/docs/xamarin-forms/navigation/passing-parameters.html
@ColeX The initial navigation part is working fine and I can see the contents on the page. But when I select an item from navigation drawer the page is not loading. I am using the following code when selecting an item from the navigation drawer.
Code execution is coming on the Homepage and but invoking the constructor without argument.
@ColeX The code execution is coming on the Homepage but invoking the constructor without argument. So is that mean our code for adding arguments to the page is not correct. I try both ways(added below) for adding arguments, but always hitting the constructor without argument.
If you call the first one , it always hits the default constructor (without argument).
If you call the second one , it hits the constructor with arguments (it is determined by the parameters passed in the MasterPageItem)
Change the code in item selected event
If
it hits
If
it hits
If
it hits
Is it clear ?
@ColeX I tried like below but showing `NavigationPage' does not contain a constructor that takes 2 arguments.
Screenshot:
.............
It should be
Detail = new NavigationPage((Page)Activator.CreateInstance(page,item.args));
Hi @ColeX
Today I tested the navigation drawer feature in ios and UWP. In ios a blue box is showing on each pages of drawer items. See the screenshot below:
In UWP the navigation drawer is not dismissing after selecting an item from it.
I searched a lot, Can you suggest any solution for these 2 issues?
This is a another question , could you open a new thread ?
@ColeX Sure.
Started a new thread here.