How would I reference the Master Detail Page (MenuNavigation) by a clickable button inside of Homepage.xaml.cs and Homepage.xaml?
I want the side menu to appear whenever I click the "menu" button. (see below)
I have tried MasterDetail.isPresentedProperty inside the clicked button event handler in Homepage.xaml.cs and cannot figure it out.
Please help!
MenuNavigation.xaml:
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="App2.MenuNavigation"
xmlns:local="clr-namespace:App2">
<!--this is the Menu Hamburger sidebar -->
<MasterDetailPage.Master>
<ContentPage Title="Menu" Padding="20" BackgroundColor="#4B1388" >
<StackLayout Orientation="Vertical">
<Label Text="Menu" TextColor="White" FontSize="Large" FontAttributes="Bold" HorizontalOptions="Center"/>
<Button Text="Home"
TextColor="White" BackgroundColor="#4B1388"
Clicked="Button_Clicked_Home"/> <!-- event handler points to MenuNavigation C# file when button is clicked-->
<Button Text="About"
TextColor="White" BackgroundColor="#4B1388"
Clicked="Button_Clicked_About"/>
<Button Text="Help"
TextColor="White" BackgroundColor="#4B1388"
Clicked="Button_Clicked_Help"/>
</StackLayout>
</ContentPage>
</MasterDetailPage.Master>
<!--links to the detail pages from the hamburger sidebar -->
<MasterDetailPage.Detail>
</MasterDetailPage.Detail>
MenuNavigation.xaml.cs:
namespace App2
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MenuNavigation : MasterDetailPage
{
public MenuNavigation()
{
InitializeComponent();
//this is for no nav bar at top
var Homepage = new Homepage();
NavigationPage.SetHasNavigationBar(Homepage, false);
Detail = new NavigationPage(Homepage);
IsPresented = false; //this will make the side menu disappear when you select a page
}
private void Button_Clicked_Home(object sender, EventArgs e)
{
var Homepage = new Homepage();
NavigationPage.SetHasNavigationBar(Homepage, false);
Detail = new NavigationPage(Homepage);
IsPresented = false; //this will make the side menu disappear when you select a page
}
private void Button_Clicked_About(object sender, EventArgs e)
{
Detail = new NavigationPage(new About());
IsPresented = false;
}
private void Button_Clicked_Help(object sender, EventArgs e)
{
Detail = new NavigationPage(new Help());
IsPresented = false;
}
}
}
Homepage.xaml:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="App2.Homepage"
Title="Homepage">
<Button Text="Menu" Clicked="MasterDetailButton_Pressed"/>
</ContentPage>
Hompage.xaml.cs:
namespace App2
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class Homepage : ContentPage
{
public Homepage()
{
InitializeComponent();
VideoListView.ItemsSource = Videos; //allows for binding
}
private void MasterDetailButton_Pressed(object sender, EventArgs e)
{
MasterDetailPage.IsPresentedProperty.Equals(true);
//open the master detail page when button is clicked.
//MasterDetailPage.IsPresentedProperty.Equals(true);
//MenuNavigation.IsPresentedProperty.Equals(true);
}
}
}
You should get a reference of your MasterDetailPage and change the IsPresented property of the reference. As the MasterDetailPage has to be the root of the app, something like this should work: (App.Current.MainPage as MasterDetailPage).IsPresented = true;.
Hope it helps! :)
Related
I'm new to the xaramin. forms and Im designing a quiz game. I want to make the button to be disabled after the user clicks it to prevent the user from choosing it again. I tried to use Isenable but it's not working.
if I miss putting some code, please point it out.
XAML CODE
<StackLayout>
<StackLayout>
<Button x:Name="C11" Text="$1" WidthRequest="50" HeightRequest="100" Clicked="C11_Clicked" />
<Button x:Name="C12" Text="$1" WidthRequest="50" HeightRequest="100" Clicked="C12_Clicked"/>
</StackLayout>
</StackLayout>
C# code
private void C11_Clicked(object sender, EventArgs e)
{
C11.IsEnabled = false;
Navigation.PushModalAsync(new C11());
}
updated part
private void continue_Clicked(object sender, EventArgs e)
{
MainPage m = new MainPage();
m.C11btn.IsEnabled = false;
Preferences.Set("ButtonEnableFlag", false);
Navigation.PushModalAsync(new MainPage());
}
protected override void OnAppearing()
{
base.OnAppearing();
var enableValue = Preferences.Get("ButtonEnableFlag", true);
MainPage m = new MainPage();
m.C11btn.IsEnabled = enableValue;
}
may i ask how to permanently disabled the button?
If you want to make the button disabled permanently, you need to save a custom status flag in device. Next time entering to this view, the button will be disabled by this custom status flag programmatically.
For example, we can use Xamarin.Essentials: Preferences to sace the custom status flag and override OnAppearing method as follows:
public partial class PageThird : ContentPage
{
public PageThird()
{
InitializeComponent();
}
private void Button_Clicked(object sender, EventArgs e)
{
MyButton.IsEnabled = false;
Preferences.Set("ButtonEnableFlag", false);
}
protected override void OnAppearing()
{
base.OnAppearing();
var enableValue = Preferences.Get("ButtonEnableFlag", true);
MyButton.IsEnabled = enableValue;
}
}
Here is the Xaml code of this page:
<ContentPage.Content>
<StackLayout Padding="20">
<Label Text="Welcome to PagePersonal!"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
<Button x:Name="MyButton" Text="Disable" Clicked="Button_Clicked"/>
</StackLayout>
</ContentPage.Content>
Now the button will be disabled permanently.
If you want to disable the button in another page, you only need to set the custom status flag in another page. Later when you back to needed page, the button will be disabled.
The another page code:
public partial class PageSecond : ContentPage
{
public PageSecond()
{
InitializeComponent();
}
private async void Button_Clicked(object sender, EventArgs e)
{
await Navigation.PushModalAsync(new PageThird());
}
private void Disable_Clicked(object sender, EventArgs e)
{
Preferences.Set("ButtonEnableFlag", false);
}
private void Enable_Clicked(object sender, EventArgs e)
{
Preferences.Set("ButtonEnableFlag", true);
}
}
Then it will work, no code need to change in the needed page.
I am learning xamaring forms,
I would like to get an Entry text from another xaml.cs file
Here my Entry in my first xaml file (content page) :
<Entry x:Name="UserName" Text="" Placeholder="enter your name" />
And in my second content page I would like to get the value : UserName.Text
I would like to use BindableProprety because I am using this Popup plugin, if there is another solution I ll take
Thanks in advance
You can solve it creating a PopupPage because you're using Rg.Plugins.Popup, place an Entry and send an event when user press a button.
I have created an small demo.
1. The ask user name popup page.
XAML
<?xml version="1.0" encoding="utf-8" ?>
<pages:PopupPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:pages="clr-namespace:Rg.Plugins.Popup.Pages;assembly=Rg.Plugins.Popup"
x:Class="xamstack.AskUserPopupPage"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
mc:Ignorable="d">
<StackLayout BackgroundColor="White" Padding="20"
VerticalOptions="Center" HorizontalOptions="Fill">
<Entry x:Name="UserEntry"/>
<Button Text="Submit" Clicked="ButtonSubmitUser_OnClicked"/>
</StackLayout>
</pages:PopupPage>
Code behind
public partial class AskUserPopupPage : PopupPage
{
public AskUserPopupPage()
{
InitializeComponent();
}
private void ButtonSubmitUser_OnClicked(object sender, EventArgs e)
{
OnUserSubmitted(UserEntry.Text);
}
public event EventHandler<string> UserSubmitted;
protected virtual void OnUserSubmitted(string e)
{
UserSubmitted?.Invoke(this, e);
}
}
2. Finally the ViewModel and the Page to display/ask the user name.
ViewModel:
public class UserPageViewModel : INotifyPropertyChanged
{
private string _userName;
public string UserName
{
get => _userName;
set
{
if (_userName != value)
{
_userName = value;
OnPropertyChanged(nameof(UserName));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Page XAML:
...
<ContentPage.BindingContext>
<UserPageViewModel/>
</ContentPage.BindingContext>
<StackLayout>
<Label Text="{Binding UserName,Mode=OneWay}"/>
<Button Text="Ask user" Clicked="ButtonAskUser_OnClicked"/>
</StackLayout>
...
Page code behind:
public partial class UserPage : ContentPage
{
public UserPage()
{
InitializeComponent();
}
private async void ButtonAskUser_OnClicked(object sender, EventArgs e)
{
var page = new AskUserPopupPage();
page.UserSubmitted += async (_, userName) =>
{
var vm = (UserPageViewModel) BindingContext;
vm.UserName = userName;
await Navigation.PopPopupAsync();
};
await Navigation.PushPopupAsync(page);
}
}
I am trying to create bottom tabbed page in Xamarin forms and i am doing this for Android.
here i am using latest version of Xamarin Forms.
My sample Bottom tabbed page like below.
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="clr-namespace:SampleTabbedPage.Views"
xmlns:android="clr-namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
android:TabbedPage.ToolbarPlacement="Bottom"
android:TabbedPage.BarItemColor="Gray"
android:TabbedPage.BarSelectedItemColor="Blue"
mc:Ignorable="d"
x:Class="SampleTabbedPage.Views.SampleTabbed">
<!--Pages can be added as references or inline-->
<NavigationPage
Title="Main"
NavigationPage.HasNavigationBar="False">
<x:Arguments>
<views:SampleDetailsPage/>
</x:Arguments>
</NavigationPage>
<ContentPage Title="Tab 1" />
<ContentPage Title="Tab 2" />
</TabbedPage>
My sample details page like
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="SampleTabbedPage.Views.SampleDetailsPage"
BackgroundColor="Gray">
<ContentPage.Content>
<StackLayout>
<ListView BackgroundColor="White" ItemTapped="ListView_ItemTapped">
<ListView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Mango</x:String>
<x:String>Banana</x:String>
<x:String>Pinaple</x:String>
<x:String>Apple</x:String>
<x:String>Avacado</x:String>
<x:String>Coconut</x:String>
<x:String>Dragan Fruit</x:String>
<x:String>Pomaganate</x:String>
<x:String>Wood Apple</x:String>
</x:Array>
</ListView.ItemsSource>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
And the navigation i am doing as follows
in App.xamal.cs
MainPage = new NavigationPage(new FirstPage());
I have simple first page
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="SampleTabbedPage.Views.FirstPage">
<ContentPage.Content>
<StackLayout>
<Button Text="Click Me!" Clicked="Button_Clicked"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
here in button click event i do the navigation to "Sample Tabbed Page"
await Navigation.PushAsync(new SampleTabbed());
This is working fine.
but there is a performance issue.
if i run this and click on button in First page it is taking 3 seconds to load tabbed page.
if i remove list view in sample detail page it take 2 seconds to load.
but if i add just a content page to click event it take only milliseconds to load.
Am i doing some thing wrong with implementing tabbed page?
or
is there any way to improve the loading performance with tabbed pages.
A solution is to make the heavy pages load their content in a lazy manner, only when their tab becomes selected. This way, since these pages are now empty when TabbedPage is created, navigating to the TabbedPage suddenly becomes very fast!
1.create a behavior for the TabbedPage page, called ActivePageTabbedPageBehavior.
class ActivePageTabbedPageBehavior : Behavior<TabbedPage>
{
protected override void OnAttachedTo(TabbedPage tabbedPage)
{
base.OnAttachedTo(tabbedPage);
tabbedPage.CurrentPageChanged += OnTabbedPageCurrentPageChanged;
}
protected override void OnDetachingFrom(TabbedPage tabbedPage)
{
base.OnDetachingFrom(tabbedPage);
tabbedPage.CurrentPageChanged -= OnTabbedPageCurrentPageChanged;
}
private void OnTabbedPageCurrentPageChanged(object sender, EventArgs e)
{
var tabbedPage = (TabbedPage)sender;
// Deactivate previously selected page
IActiveAware prevActiveAwarePage = tabbedPage.Children.OfType<IActiveAware>()
.FirstOrDefault(c => c.IsActive && tabbedPage.CurrentPage != c);
if (prevActiveAwarePage != null)
{
prevActiveAwarePage.IsActive = false;
}
// Activate selected page
if (tabbedPage.CurrentPage is IActiveAware activeAwarePage)
{
activeAwarePage.IsActive = true;
}
}
}
2.define IActiveAware interface
interface IActiveAware
{
bool IsActive { get; set; }
event EventHandler IsActiveChanged;
}
3.create a base generic abstract class called LoadContentOnActivateBehavior
abstract class LoadContentOnActivateBehavior<TActivateAwareElement> : Behavior<TActivateAwareElement>
where TActivateAwareElement : VisualElement
{
public DataTemplate ContentTemplate { get; set; }
protected override void OnAttachedTo(TActivateAwareElement element)
{
base.OnAttachedTo(element);
(element as IActiveAware).IsActiveChanged += OnIsActiveChanged;
}
protected override void OnDetachingFrom(TActivateAwareElement element)
{
(element as IActiveAware).IsActiveChanged -= OnIsActiveChanged;
base.OnDetachingFrom(element);
}
void OnIsActiveChanged(object sender, EventArgs e)
{
var element = (TActivateAwareElement)sender;
element.Behaviors.Remove(this);
SetContent(element, (View)ContentTemplate.CreateContent());
}
protected abstract void SetContent(TActivateAwareElement element, View contentView);
}
4.the specialized LazyContentPageBehavior
class LazyContentPageBehavior : LoadContentOnActivateBehavior<ContentView>
{
protected override void SetContent(ContentView element, View contentView)
{
element.Content = contentView;
}
}
then we can use in xaml like this:
<TabbedPage>
<TabbedPage.Behaviors>
<local:ActivePageTabbedPageBehavior />
</TabbedPage.Behaviors>
<ContentPage Title="First tab">
<Label Text="First tab layout" />
</ContentPage>
<local:LazyLoadedContentPage Title="Second tab">
<ContentPage.Behaviors>
<local:LazyContentPageBehavior ContentTemplate="{StaticResource ContentTemplate}" />
</ContentPage.Behaviors>
<ContentPage.Resources>
<ResourceDictionary>
<DataTemplate x:Key="ContentTemplate">
<!-- Complex and slow to render layout -->
<local:SlowContentView />
</DataTemplate>
</ResourceDictionary>
</ContentPage.Resources>
</local:LazyLoadedContentPage>
</TabbedPage>
we moved the ContentPage complex layout to become a DataTemplate.
Here's the custom LazyLoadedContentPage page which is activation aware:
class LazyLoadedContentPage : ContentPage, IActiveAware
{
public event EventHandler IsActiveChanged;
bool _isActive;
public bool IsActive
{
get => _isActive;
set
{
if (_isActive != value)
{
_isActive = value;
IsActiveChanged?.Invoke(this, EventArgs.Empty);
}
}
}
}
SlowContentView do some complex things
public partial class SlowContentView : ContentView
{
public SlowContentView()
{
InitializeComponent();
// Simulating a complex view
...
}
}
I am experiencing a weird bug where a Custom effect would affect other Controls as well while i am only targeting one specific control. I was able to reproduce the behavior in a small test project. What i am trying to achieve is to change the color of a specific entry control. It does work but when navigating back to the previous page the effect affects other controls as well while i only want the specific effect to affect a specific control. I also only add the effect to the specific Entry by using its Effects list from xaml.
(note i am using the standard forms navigation page for navigating defined in my app.xaml like this.
MainPage = new NavigationPage(new MainPage());
MainPage.xaml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:App2"
x:Class="App2.MainPage">
<StackLayout>
<!-- Place new controls here -->
<Label Text="Welcome to Xamarin.Forms!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Entry></Entry>
<Button Clicked="Button_Clicked" Text="navigate"></Button>
<Button Clicked="Button_Clicked2" Text="navigate to other"></Button>
</StackLayout>
</ContentPage>
CodeBehind of MainPage.xaml
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
private void Button_Clicked(object sender, EventArgs e)
{
Application.Current.MainPage.Navigation.PushAsync(new Test());
}
private void Button_Clicked2(object sender, EventArgs e)
{
Application.Current.MainPage.Navigation.PushAsync(new Test2());
}
}
Test.Xaml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:App2"
x:Class="App2.Test">
<ContentPage.Content>
<Entry>
<Entry.Effects>
<local:EntryLineColorEffect></local:EntryLineColorEffect>
</Entry.Effects>
</Entry>
</ContentPage.Content>
</ContentPage>
Test2.xaml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="App2.Test2">
<ContentPage.Content>
<StackLayout>
<Label Text="test 2" />
<Entry>
</Entry>
</StackLayout>
</ContentPage.Content>
</ContentPage>
EntryLineColorEffect (forms project)
public class EntryLineColorEffect : RoutingEffect
{
public EntryLineColorEffect() : base("Prolang.EntryLineColorEffect")
{
}
}
EntryLineColorEffect (Android project)
[assembly: ResolutionGroupName("Prolang")]
[assembly: ExportEffect(typeof(EntryLineColorEffect), "EntryLineColorEffect")]
namespace App2.Droid.Effects
{
class EntryLineColorEffect : PlatformEffect
{
EditText control;
protected override void OnAttached()
{
control = Control as EditText;
UpdateLineColor();
}
protected override void OnDetached()
{
control = null;
}
private void UpdateLineColor()
{
if (control != null)
{
control.Background.SetColorFilter(Color.DarkMagenta.ToAndroid(), Android.Graphics.PorterDuff.Mode.SrcAtop);
}
}
}
}
some screenshots that make it more clear
The entry does get the Magenta color which is good
But when navigating back and then navigating to the Test2 page that entry is also getting the Magenta color which for me is undesired behavior (and i do not know why it is hapenning). So what should i do to avoid this behavior?
In the end someone on the Xamarin comunity forum was able to answer my question.
=>
Effect won't affect other controls which haven't attached that effect. It seems Background.SetColorFilter(Color.DarkMagenta.ToAndroid(), Android.Graphics.PorterDuff.Mode.SrcAtop); changes the global Entry's underline's color. The entry displayed later after this setting will apply this behavior. So your Test2's Entry still has an attacted style. Use Background.Mutate().SetColorFilter(Color.DarkMagenta.ToAndroid(), Android.Graphics.PorterDuff.Mode.SrcAtop); instead to correct that:
EditText control;
protected override void OnAttached()
{
control = Control as EditText;
UpdateLineColor();
}
protected override void OnDetached()
{
control = null;
}
private void UpdateLineColor()
{
if (control != null)
{
control.Background.Mutate().SetColorFilter(Color.DarkMagenta.ToAndroid(), Android.Graphics.PorterDuff.Mode.SrcAtop);
}
}
I cant find a way to implement an onClick event on a button that will allow the application to navigate between the login and the second view.
How can I do that ?
Here is what i did
I created a method in my LoginViewModel.cs file that should redirect me to the second view.
class LoginViewModel
{
private async Task SecondView_Click()
{
App.Current.MainPage = new NavigationPage(new SecondView());
}
}
Then I've defined a BindingContext in my Login.cs
public partial class Login : ContentPage
{
public Login()
{
InitializeComponent();
BindingContext = new LoginViewModel();
}
}
Then I define a button in my Login.xaml that has a binded command property
<StackLayout
VerticalOptions="CenterAndExpand">
<Entry StyleId="UsernameEntry"
Placeholder="Username"
Text="{Binding Username}" />
<Entry StyleId="PasswordEntry"
Placeholder="password"
Text="{Binding Password}" />
<Button
StyleId="btn_connexion"
Text="Connexion"
Command="{Binding connexion}" />
<Button
StyleId="btn_testSecondView"
Text="Test 2nd View"
Command="{Binding SecondView_Click}"></Button>
</StackLayout>
This works for me
PAGE 1 XAML
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="TestRelativeLayout.MyPage1"
Title="TabbedPage">
<StackLayout>
<Button Clicked="Handle_Clicked" Text = "Press">
</Button>
</StackLayout>
</ContentPage>
PAGE 1 XAML.CS
using Xamarin.Forms;
namespace TestRelativeLayout
{
public partial class MyPage1 : ContentPage
{
public MyPage1()
{
InitializeComponent();
}
public void Handle_Clicked(object sender, System.EventArgs e)
{
Application.Current.MainPage = new NavigationPage(new MyPage2());
}
}
}
Try to remove
private async Task
and use
void
private async Task SecondView_Click()
{
App.Current.MainPage = new NavigationPage(new SecondView());
}
Here is what I did.
I found that there is a "clicked" property on that prompt an intellisense dropdown with a "new event handler".
<StackLayout
VerticalOptions="CenterAndExpand">
<Entry StyleId="UsernameEntry"
Placeholder="Username"
Text="{Binding Username}" />
<Entry StyleId="PasswordEntry"
Placeholder="password"
Text="{Binding Password}" />
<Button
StyleId="btn_connexion"
Text="Connexion"
Clicked="connexion" />
<Button
StyleId="btn_testSecondView"
Text="Test 2nd View"
Clicked="SecondView_Click"></Button>
</StackLayout>
Once i did that it created a method in the code behind "Login.xaml.cs".
From there I just paste the navigation method and it worked
private async Task SecondView_Click()
{
App.Current.MainPage = new NavigationPage(new SecondView());
}
The fact that it is a PCL project makes it difficult to find the right information because everything you find on the internet concerns the ios/android solution and not the portable solution.