How to display content page half the screen size in Xamarin Forms? - xamarin

I am working on a Xamarin Forms project and need to achieve the following:
On Navigating from Home Page to a new Page, the new page will have a menu button, some text fields and a signature button. When we click on Menu Button, a menu page should slide down. The slide menu page should have a navigation bar and should be able to navigate to other sub menu options.
The slide menu page should overlap current content page. Is there any way to achieve it ?

Slide menu will just be determined by what packages you want to use or if you want to create animations with ResourceDictionary/VisualStateManager but to get it to be half the size of the page dynamically you can use something like:
XAML:
<Page x:Name="Page" HeightRequest="{Binding PageHeight, Mode=TwoWay}"></Page>
<Menu x:Name="Menu" HeightRequest="{Binding MenuHeight}"></Menu>
XAML.CS:
public class YourPage : YourType //(ContentViews for me)
private YourViewModel ViewModel => (YourViewModel)this.BindingContext;
public YourPage()
{
this.BindingContext = YourVM;
}
VM.CS:
public class YourViewModel : INotifyPropertyChanged
private double _pageHeight;
public double PageHeight
{
set
{
if (_pageHeight != value)
{
_pageHeight = value;
OnPropertyChanged("PageHeight");
PageHeightChanged("PageHeight");
}
}
get
{
return _pageHeight;
}
}
private double _menuHeight;
public double MenuHeight
{
set
{
if (_menuHeight != value)
{
_menuHeight = value;
OnPropertyChanged("MenuHeight");
}
}
get
{
return _menuHeight;
}
}
private void PageHeightChanged()
{
Menu.HeightRequest = Page.Height/2;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

Related

Navigating from a Contentpage to a TabbedPage

I have a Content page that is a Contains a list of items.
Then I have a TabbedPage that represents one of this items splitted (each tab represents a section of the item.. Categories, periods, etc)
Now, I want to click on the item of my list (contentPage) and navigate to the item (TabbedPage).
I tried with Navigation.PushAsync which works fine for me on IOS, however on Android I have an exception:
System.InvalidCastException: 'Specified cast is not valid.'
public partial class BudgetsPage : ContentPage
{
//...
async void OnItemSelected(object sender, EventArgs args)
{
var layout = (BindableObject)sender;
var item = (BudgetItem)layout.BindingContext;
var budgetManagement = new BudgetManagementPage(new BudgetDetailViewModel(item));
await Navigation.PushAsync(budgetManagement);
}
}
And the Tabbed page is something like
public partial class BudgetManagementPage : TabbedPage
{
public BudgetManagementPage(BudgetDetailViewModel viewModel)
{
InitializeComponent();
budgetManagementPage.Children.Add(new NavigationPage(new BudgetInfoTab(viewModel)) { IconImageSource = GetImageSource(IconFont.Information), Title="Info"});
}
private ImageSource GetImageSource(string iconName)
{
return new FontImageSource()
{
FontFamily = "materialWebFont",
Glyph = iconName
};
}
}
Somehow it looks like Android isn't expecting the tabbedpage on pushingAsync?
Does anyone had the same issue?

Is there a way to update bounded data when I swipe back [PopAsync() ]

To provide some context, I'm writing a Xamarin.Forms application and utilizing data binding with INotifyPropertyChanged. Currently I have an inventory counter displayed on a button. The text on this button displays the bounded "Count" variable (e.g Current Inventory: 35). When I press the button, I push a screen onto the navigation stack which allows me to edit this "Count" variable. I use the class implementation like this
public class UserInventory : INotifyPropertyChanged
{
private int count = 0;
// Declare the event
public event PropertyChangedEventHandler PropertyChanged;
public int Count
{
get => Preferences.Get(nameof(Count),0);
set
{
if (count == value || value <1)
return;
Preferences.Set(nameof(Count), value);
//count = value;
//Application.Current.Properties["Count"] = count;
OnPropertyChanged(nameof(Count));
//OnPropertyChanged(nameof(displayName));
}
}
public UserInventory()
{
}
void OnPropertyChanged(string count)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(count));
}
}
I add this class in Xaml according to the tutorial on the Xamarin <ContentPage.BindingContext>
<local:UserInventory />
</ContentPage.BindingContext>
So the variables are bounded correctly and I have no issues seeing updates on the current page or when I push new pages. The issue is when I swipe back on iOS the previous screen with the button "Current Inventory: 35" does not update to reflect the new changes. If I push that screen the changes are reflected.
Is there anyway to ensure the bounded data is updated when you go back (PopAsync()) ?
Try overriding page's OnAppearing() method and call OnPropertyChanged from there.
Assuming 'UserInventory' the binded VM.....
public partial class Page1:ContentPage
{
public Page1()
{
InitializeComponent();
VM = (UserInventory)BindingContext;
}
public UserInventory VM { get; }
protected override void OnAppearing()
{
VM.Notify();
base.OnAppearing();
}
}
.
public class UserInventory: INotifyPropertyChanged
{
........
public void Notify()
{
OnPropertyChanged(nameof(Count));
}
}

Xamarin Tabbed Page not showing Content

trying to learn more about Tabbed Pages with i've built a very simple App containing three content Pages with a code like this:
public class Page1 : ContentPage
{
public Page1()
{
Content = new StackLayout
{
Children = {
new Label { Text = "Hello Page1" }
}
};
}
protected override void OnAppearing()
{
base.OnAppearing();
System.Diagnostics.Debug.WriteLine("Page 1 On Appearing");
}
protected override void OnDisappearing()
{
base.OnDisappearing();
System.Diagnostics.Debug.WriteLine("Page 1 Disappearing");
}
}
The Main Page looks like this:
public class MainPage : TabbedPage
{
public MainPage()
{
var page1 = new Page1();
page1.Title = "Page1";
var page2 = new Page2();
page2.Title = "Page2";
var page3 = new Page3();
page3.Title = "Page3";
Children.Add(page1);
Children.Add(page2);
Children.Add(page3);
}
}
Now when i click on a new tab, the OnDisappearing() method of the old tab is called, as well as the OnAppearing() method of new tab, BUT the content of the new page is not shown. It remains the content of the old page.
To show the content of the new page i have to click again on the tab.
Does anybody has experienced this kind of behaviour?
Best regards,
Marco

Create a Layout Item for ListView in Xamarin Android

I have a problem and It's 10 days that I am working and can't solve it.I made a layout for each row for ListView.This Layout Contains a linearLayout that there is a TextView and a WebView inside it.Now I Need a C# Project that I can add a new Row to the ListView with new text and url whenever I want.For Example: button.click { ListView.add(Resource.Layout.Items, "Text","Url")}..I know this command is wrong. Just I wanted to clear the problem for you.
I khnow it's custom Row layout and I read manny examples at this site other sites and Xamarin site about that,adapters,... but I can't do it. :(
Please answer me correctly.
It is very important for me.
Thanks a lot.
You need to create an adapter that can work with you custom objects as items. It could look like the following sample:
public class MyAdapter : BaseAdapter<MyItem>
{
readonly LayoutInflater inflater;
List<MyItem> myItemList;
public MyAdapter(Context context)
{
inflater = LayoutInflater.FromContext(context);
myItemList = YOUR_DATASOURCE.GetMyItems();
}
public override MyItem this [int index]
{
get { return myItemList[index]; }
}
public override int Count
{
get { return myItemList.Count; }
}
public override long GetItemId(int position)
{
return position;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
View view = convertView ?? inflater.Inflate(Resource.Layout.MyItemLayout, parent, false);
var item = myItemList[position];
var viewHolder = view.Tag as MyViewHolder;
if (viewHolder == null)
{
viewHolder = new MyViewHolder();
viewHolder.Web = view.FindViewById<WebView>(Resource.Id.MyItemLayout_Icon);
viewHolder.Name = view.FindViewById<TextView>(Resource.Id.MyItemLayout_Title);
view.Tag = viewHolder;
}
viewHolder.Web.Url = item.Url; //You need to check how you have to set the url for a WebView
viewHolder.Name.Text = item.Text;
return view;
}
public override void NotifyDataSetChanged()
{
myItemList = YOUR_DATASOURCE.GetMyItems();
base.NotifyDataSetChanged();
}
}
class MyViewHolder : Java.Lang.Object
{
public WebView Web { get; set; }
public TextView Name { get; set; }
}
You apply the adapter to your ListView with ListView.Adapter = new MyAdapter(Activity);. Each time you change an item in you button click event, you tricker (ListView.Adapter as MyAdapter).NotifyDataSetChanged(); which will force the adapter to reload and refresh the data.
YOUR_DATASOURCE represents the point in your code where you store the informations like the url or text of all your items. This could typically be a database or something similar. While GetMyItems() is a method for example to query your database.
Hope this clears things up.

Xamarin.Forms Disable slide menu in pushed page

I use Xamarin.Forms (ver 1.4)
Page hierarchy:
->NavigationPage
-->MasterDetailPage
How can disable sliding menu (open master page by gesture) in pushed screen?
Push method:
await ((NavigationPage)((MasterDetailPage)Application.Current.MainPage).Detail).PushAsync(page))
Sliding menu should work only on root page.
MasterMenuPage holds a bool property called "IsGestureEnabled" which determines if the swipe in menu is available.
IsGestureEnabled = false //no swipe gesture
Here I can give you an easy implementation for a custom MasterDetailPage
public class MainMDPage : MasterDetailPage
{
public MainMDPage(Page masterPage, Page detailPage)
{
MasterBehavior = MasterBehavior.Popover;
Master = masterPage;
Detail = detailPage;
}
/// <summary>
/// Pushes a page and disables the master menu.
/// </summary>
/// <param name="page"></param>
/// <returns></returns>
public async Task PushAsync(Page page)
{
if(Detail is NavigationPage navPage)
{
await navPage.PushAsync(page);
IsGestureEnabled = false;
}
}
/// <summary>
/// Pops a page and enables the master menu if we get to the root page.
/// </summary>
/// <returns></returns>
public async Task PopAsync()
{
if (Detail is NavigationPage navPage)
{
await navPage.PopAsync();
if (navPage.Navigation.NavigationStack.Count == 1) //if count == 1 -> is root page
IsGestureEnabled = true;
}
}
}
In my app, I have "RootPage" that inherits from MasterDetailPage. This is my MainPage for the Application. I have a "MenuPage" that inherits from ContentPage that creates the menu items. I set that to Master in "RootPage". Then I create a new NavigationPage, passing in page with a list view to the constructor. I then set the Detail to the NavigationPage. In the listview page, OnItemSelected I navigate with Navigation.PushAsync(detailsPage). Following this pattern, when the detailsPage loads, the "hamburger/sliding menu" is not there in iOS and instead I can only go back to the previous page (List view). Here are code examples:
public class RootPage : MasterDetailPage {
MenuPage menuPage;
public RootPage() {
menuPage = new MenuPage();
menuPage.Menu.ItemSelected += (sender, e) =>
NavigateTo(e.SelectedItem as Model.MenuItem);
Master = menuPage;
Detail = new NavigationPage(PlayerListPage());
}
}
public class PlayerListPage : ContentPage {
protected async void OnItemSelected(object sender, ItemTappedEventArgs e) {
var item = e.Item as PlayerViewModel;
var selected = new PlayerPage(item) {
BindingContext = item
};
await Navigation.PushAsync(selected);
}
}
public class MenuPage : ContentPage {
public ListView Menu { get; set; }
public MenuPage() {
Icon = "menu.png";
Title = "menu"; // The Title property must be set.
var menuItems = new List<MenuItem> {
new MenuItem {
Title = "Players",
IconSource = "people.png",
TargetType = typeof(PlayerListPage)
},
};
Menu = new ListView {
ItemsSource = menuItems,
};
}
}
public class MenuItem {
public string Title { get; set; }
public string IconSource { get; set; }
public Type TargetType { get; set; }
}
Is this what you are trying to achieve? If not, then you clarify what you mean by disable the sliding menu and provide more code samples.

Resources