Custom navigation bar using Xamarin forms with prism broken - xamarin

I'm using Prism Library for Xamarin.Forms.
And I'm going to create custom navigation bar via Control template. (Reason of creating custom navigation bar - I didn't find solution to make navigation bar transparent for display background image, also I will probably customize my navigation bar and add some controls on it).
<ControlTemplate x:Key="NavigationPageTemplate">
<AbsoluteLayout BackgroundColor="Transparent">
<Image AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All"
Aspect="AspectFill"
Source="{TemplateBinding BackgroundImageEx}" />
<ContentView Padding="0,50,0,0"
AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All">
<ContentPresenter />
</ContentView>
<!--Navigation bar started here -->
<ContentView AbsoluteLayout.LayoutBounds="0,0,1,AutoSize"
AbsoluteLayout.LayoutFlags="PositionProportional, WidthProportional"
BackgroundColor="Transparent">
<ContentView.Padding>
<OnPlatform x:TypeArguments="Thickness"
Android="10"
iOS="10, 20, 10, 0" />
</ContentView.Padding>
<controls:ImageButton Command="{TemplateBinding GoBackCommand}"
HeightRequest="30"
HorizontalOptions="StartAndExpand"
Source="ic_back.png"
WidthRequest="30">
</controls:ImageButton>
</ContentView>
</AbsoluteLayout>
</ControlTemplate>
And my problem is to process back button press with Prism Navigation.
I've tried to process click on MyApp.xaml.cs file.
private void Button_OnClicked(object sender, EventArgs e)
{
NavigationService.GoBackAsync();
}
And it seems to have different navigation stack because it shows after press my first page.
I had Navigation this way:
Navigate("FirstPage"); -> Navigate(MasterDetail/NavigationPage/ViewA) -> Navigate("ViewB")
ViewB - uses Control template.
When I click custom back button on ViewB NavigationService back me to FirstPage. It is incorrect for me. I should back to ViewA!
Another question Should first page be saved when we change App.MainPage?

See the discussion of described problem on https://github.com/PrismLibrary/Prism/issues/1262

To navigate back from ViewA to FirstPage you can intercept the back event and go back again if a variable is passed with a specific value from the ViewB page. Code Example:
Sender:
var navigationParams = new NavigationParameters();
navigationParams.Add("yourVariableName", "YourVariableValue");
_navigationService.GoBackAsync(navigationParams);
Receiver:
public void OnNavigatedTo(NavigationParameters parameters)
{
string myVar = null;
if (parameters.ContainsKey("yourVariableName"))
{
myVar = (string)parameters["yourVariableName"];
}
if(myVar=="YourVariableValue"){
NavigationService.GoBackAsync();
}
}
I don't understand your second question.

Related

XAMARIN Button with Label and image inside / mainpage=navigation page

I am fairly new and inexperienced. I have two questions. First: what would the xaml code in xamarin look like for such a button? The blue one should be the button. The button should contain a text and a picture. So it should also work that when the image or text is clicked, the button is actually clicked.
enter image description here
Second: my app has two sides. The start page is MainPage and the other page is Page1. I can switch to Page1 using a button on MainPage. I looked at a tutorial and in App.xaml.cs "MainPage = new MainPage ();" was made to "MainPage = new NavigationPage (new MainPage ());". Why was that done? Why does the page change via a button click not work differently?
enter image description here
Since it was coded to "MainPage = new NavigationPage (new MainPage ());" , there is a blue bar at the top of my MainPage. How can I remove this bar or make it white?
enter image description here
For the first question:
There is no such control now, but you can do this by using a Frame and adding an Image and Label to it,then you could add a TapGestureRecognizer to the Frame.
like:
<Frame CornerRadius="20" HorizontalOptions="Start" WidthRequest="100" HeightRequest="120" BackgroundColor="Blue" Padding="40">
<StackLayout Orientation="Vertical" >
<Image Source="heart.png"></Image>
<Label Text="hello world" BackgroundColor="Red" ></Label>
</StackLayout>
<Frame.GestureRecognizers>
<TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped">
</TapGestureRecognizer>
</Frame.GestureRecognizers>
</Frame>
handle the click event in code behind:
private void TapGestureRecognizer_Tapped(object sender, EventArgs e)
{
//do something
}
For the second question:
1)To move from one page to another, an application will push a new page onto the navigation stack.The NavigationPage class provides a hierarchical navigation experience where the user is able to navigate through pages, forwards and backwards, as desired. The class implements navigation as a last-in, first-out (LIFO) stack of Page objects.
2)The top blue bar we call it NavigationBar.If you want display it,you could set NavigationPage.SetHasNavigationBar(this, false); in your MainPage.xaml.cs like:
public MainPage()
{
InitializeComponent();
NavigationPage.SetHasNavigationBar(this, false);
}
or set it in the MainPage.xaml like:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
NavigationPage.HasNavigationBar="False"
x:Class="YourNamespace.MainPage">
....
</ContentPage >
You could look at https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/navigation/hierarchical for more details.

How to make ActivityIndicator overlay full screen?

I have a StackLayout and a number of elements inside (buttons, texts etc).
I want the ActivityIndicator to overlay the entire screen and make it not able to do anything to those elements.
I have put ActivityIndicator inside the StackLayout but wrapped it with AbsoluteLayout thinking that AbsoluteLayout can easitly overlap everything:
<StackLayout>
<AbsoluteLayout>
<ActivityIndicator ... />
</AbsoluteLayout>
<...other elements...>
</StackLayout>
Instead activity indicator is displayed at the top of the StackLayout and other elements are available for affecting. I'm new in Xamarin and layouts, what am I doing wrong? All samples in the Internet have single ActivityIndicator per page...
It is better said that an AbsoluteLayout's children can easily overlap each other. Just as a StackLayout lets you stack controls inside , vertically or horizontally, an AbsoluteLayout lets you position controls inside using absolute or proportional values, thus if two controls have the same absolute positioning set, they will overlap 100%.
Therefore, you want to wrap your StackLayout and another StackLayout that has your ActivityIndicator inside an AbsoluteLayout using proportional sizing, e.g:
<AbsoluteLayout>
<StackLayout
x:Name="mainLayout"
AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All" >
<Label Text="Welcome to Xamarin.Forms!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Button Text="Do Something"
Clicked="DoSomethingBtn_Clicked" />
</StackLayout>
<StackLayout
x:Name="aiLayout"
IsVisible="False"
AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All"
BackgroundColor="Gray" Opacity="0.5">
<ActivityIndicator
x:Name="ai"
IsRunning="False"
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand"
Color="Black"/>
</StackLayout>
</AbsoluteLayout>
The above sets the two StackLayouts to both take up the full size of the parent container of the AbsoluteLayout, which is presumably a Page. The StackLayout that has the indicator is initially hidden. IN the page code behind for the above example, I show the second StackLayout and start the activity indicator and show it for 2 seconds, and then hide it again:
private async void DoSomethingBtn_Clicked(object sender, EventArgs e)
{
ai.IsRunning = true;
aiLayout.IsVisible = true;
await Task.Delay(2000);
aiLayout.IsVisible = false;
ai.IsRunning = false;
}
Here is what it looks like:
And since the second StackLayout completely covers the first, none of the controls in the first StackLayout are clickable.
Might be worth going over the docs for the AbsoluteLayout to understand the AbsoluteLayout.LayoutBounds and AbsoluteLayout.LayoutFlags:
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/layouts/absolute-layout
If you want to "overlap", you need to be outside of the StackLayout. A Grid is the most common control for this:
<Grid>
<StackLayout>
<...other elements...>
</StackLayout>
<ActivityIndicator ... />
</Grid>
Here's a hacked-up control for making things full-screen via the horribly-named RelativeLayout (tested in Android only)
[ContentProperty("ContentInner")]
public class FullScreenLayout : ContentView
{
public View ContentInner
{
get => ((RelativeLayout) Content).Children[0];
set
{
var display = DeviceDisplay.MainDisplayInfo;
var screenWidth = display.Width / display.Density;
var screenHeight = display.Height / display.Density;
var wrapper = new RelativeLayout();
wrapper.Children.Add(value, () => new Rectangle(0, 0, screenWidth, screenHeight));
Content = wrapper;
}
}
}
It can be used like this:
<controls:FullScreenLayout>
<!-- Anything you want fullscreen here -->
</controls:FullScreenLayout>
Unfortunately, if you use NavigationPage, this won't overlap the navigation bar. Every other solution currently on this page has the same issue. According to this question, it's not possible to solve this without using platform-specific customer renderers. Ugh.
If you don't mind the page being dimmed, you can use Rg.Plugins.Popup which implements the custom renderers needed.
I ended up solving my similar problem (dimming most of the screen) by implementing a custom renderer for the navigation page itself.

Xamarin Forms: System.ObjectDisposedException when setting Focus to an Entry control

I have the following Xamarin Forms page that throws an exception on this line...
The first time this page is loaded, the OnAppearing works fine, sets the focus properly, and doesn't throw an exception.
When I navigate back to this page (ie, logout), OnAppearing is throwing the following...
System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'Xamarin.Forms.Platform.Android.EntryRenderer'.
What is the best way to set focus to a control on a page in Xamarin Forms?
I'm not sure what is in your XAML, but if you define the x:Name="_entry" on the Entry in XAML, and use that name to access the control directly instead of FindByName, it should work fine.
I try to reproduce your issue at my side, but it works fine and there is no issue when I click Button to navigate another page and coming back. Please take a look my code:
<StackLayout>
<Label
HorizontalOptions="CenterAndExpand"
Text="Welcome to Xamarin.Forms!"
VerticalOptions="CenterAndExpand" />
<Entry
x:Name="UserNameentry"
HorizontalOptions="FillAndExpand"
VerticalOptions="CenterAndExpand" />
<Button
x:Name="btn1"
Clicked="btn1_Clicked"
HeightRequest="50"
HorizontalOptions="FillAndExpand"
Text="btn1"
VerticalOptions="CenterAndExpand"
WidthRequest="200" />
</StackLayout>
public Page4()
{
InitializeComponent();
}
protected override void OnAppearing()
{
base.OnAppearing();
var usernameentry = FindByName("UserNameentry") as Entry;
usernameentry.Focus();
}
private async void btn1_Clicked(object sender, EventArgs e)
{
Page3 page = new Page3();
await Navigation.PushModalAsync(page);
}
If you still have this issue, please provide some code about xaml here.

Xamarin Forms Search Bar with Picker

I have a xamarin forms app and I would like to use the search bar control that upon focus will pull up a picker. Is there anyway I can extend the search bar to provide this functionality? In other words I don’t want the user to enter text in the search bar box, rather it’s selected from the pick list. Any examples would be appreciated.
You can look at using the XFX Controls for Xamarin Forms.
https://github.com/XamFormsExtended/Xfx.Controls
In the top of your page add a namespace reference to :
xmlns:xfx="clr-namespace:Xfx;assembly=Xfx.Controls"
Then you use the control as follows:
<!-- XfxComboBox-->
<xfx:XfxComboBox
Placeholder="Select make"
SelectedItem="{Binding SelectedVehicleMake}"
Text="{Binding Description}"
ItemsSource="{Binding AssetMakes}"/>
This control allows to bind to a item source and a selected Item
Picker dialog is shown when you call Focus() on the element, so you could just place a hidden Picker and call the method from the Click Handler of the ToolbarItem.
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyApp.Views.MyPage"
Title="My Page Title"
x:Name="MyPage">
<ContentPage.ToolbarItems>
<ToolbarItem Text="ShowPicker" Clicked="ShowPicker">
</ToolbarItem>
</ContentPage.ToolbarItems>
<ContentPage.Content>
<DatePicker x:Name="MyPicker" IsVisible="false" />
</ContentPage.Content>
</ContentPage>
namespace MyApp.Views
{
public partial class MyPage : ContentPage
{
public ItemsPage()
{
InitializeComponent();
}
void ShowPicker(object sender, EventArgs e)
{
MyPicker.Focus();
}
}
}

WPF4: How do you set a value in a UserControl from the Main Window?

This has to be simple, at least it was in good old .Net where it took maybe four lines of code. I'm working in VS2010, C#, WPF4.
I have a user control with a textbox. When I click a button in the main window, I want my user control textbox to reflect some text. Is this possible in WPF4 with less than 500 lines of esoteric code?
The problem is that while I know the textbox is getting the new text as evidenced from breakpoints in the user control code, that text is never being reflected to the main window. The main window still shows the original text. It has to be some kind of binding thing, and I really don't think I should have to create templates and resources and all for this simple situation. It's got to be something simple that I'm forgetting in the forest of WPF4. Below is what I have. After clicking the button, the textbox is still blank; it does not say "hello earthlings."
In the user control code:
public partial class UserControl1 : UserControl
{
public static readonly DependencyProperty TextProperty;
public UserControl1()
{
InitializeComponent();
}
static UserControl1()
{
TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(UserControl1), new UIPropertyMetadata(null));
}
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
}
User control xaml:
<UserControl x:Class="WTFUserControlLibrary.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
<Grid Height="164" Width="220">
<TextBox Name="txtTest" BorderBrush="red" BorderThickness="2" Height="25" Text="{Binding ElementName=UserControl1, Path=Text, Mode=TwoWay}"></TextBox>
</Grid>
(I have no idea what the text binding is supposed to be doing in this case.)
Main window code:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
WTFUserControlLibrary.UserControl1 uc = new WTFUserControlLibrary.UserControl1();
uc.Text = "hello earthlings";
}
}
and the main window xaml:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:WTFUserControlLibrary;assembly=WTFUserControlLibrary"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="71,65,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
<my:UserControl1 HorizontalAlignment="Left" Margin="71,94,0,0" Name="userControl11" VerticalAlignment="Top" Height="116" Width="244" />
</Grid>
Thanks Earthlings (and also those who designed this mess!)
In your method button1_Click you are creating a new user control. This is not the usercontrol in the window and is never displayed.
Instead, give your usercontrol a name in the XAML:
x:Name="uc"
Then in the button1_Click method you just remove that first line where you create a new usercontrol.
update
You want the user control XAML to look more like this:
<UserControl x:Class="WTFUserControlLibrary.UserControl1"
x:Name="thisControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
<Grid Height="164" Width="220">
<TextBox Name="txtTest" BorderBrush="red"
BorderThickness="2" Height="25"
Text="{Binding ElementName=thisControl, Path=Text, Mode=TwoWay}" />
</Grid>
I added x:Name="thisControl" to the root UserControl element, and then referenced this in the binding.
I'll try to explain the binding:
You have this textbox inside your user control, but you want to be able to bind the text value to something outside the user control. What you've done is set up a dependency property on the user control, and bound that textbox to it, so you are using the binding infrastructure pass values from the top level of the UserControl to constituent controls inside it.
Basically, it looks like this:
data
---> bind UserControl1.Text to data
---> bind TextBox.Text to UserControl1.Text

Resources