I am trying to apply background image to all pages within my Xamarin.Forms app using an application style, but it is not applying the style to the pages.
I tried with this:
App.xaml resources
...
<Application.Resources>
<ResourceDictionary>
<Style TargetType="Page">
<Setter Property="BackgroundImageSource" Value="logo.png"/>
</Style>
...
MainPage.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"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="FinansovoPregledi.MainPage">
<StackLayout Spacing="10" VerticalOptions="Center">
<Button Text="Login" BackgroundColor="#006BE6" x:Name="scanButton" TextColor="WhiteSmoke" Command="{Binding LogInCommand}"/>
</StackLayout>
</ContentPage>
MainPage.xaml.cs
public partial class MainPage : ContentPage
{
LoginViewModel loginViewModel = new LoginViewModel();
public MainPage()
{
InitializeComponent();
BindingContext = loginViewModel;
}
...
This isn't working. In my scenario the background image has a white background with transparency.
ContentPage is derived from Page and for your style to apply to Pages as well as all controls derived from Pages you need to set the ApplyToDerivedTypes property of your style to True.
Your style would need to be
<Style ApplyToDerivedTypes="True" TargetType="Page">
<Setter Property="BackgroundImageSource" Value="logo.png"/>
</Style>
Another approach would be to set the TargetType to ContentPage
<Style TargetType="ContentPage">
<Setter Property="BackgroundImageSource" Value="logo.png"/>
</Style>
Related
I'm building a mobile app as a learning/hobby project and was curious about how far I can push the designs in a xamarin app. Is there a way to present a consistent backplane or image in an app that employs MasterDetailPage in the mainview? The effect I'm trying to accomplish is when each page is shown, which would have a transparent background, the app background never changes or is part of the page transition at all.
A.
Since any page type (Shell, NavigationPage, ContentPage, etc) that derives from Page has a BackgroundImageSource property, you can define the value globally in App.xaml.
<Application.Resources>
<Style ApplyToDerivedTypes="True" TargetType="Page">
<Setter Property="BackgroundImageSource" Value="your_image.png" />
</Style>
</Application.Resources>
B.
Well, if you wanna apply it just for MasterDetail pages, you can just set the style for NavigationPage only.
<Application.Resources>
<Style TargetType="NavigationPage">
<Setter Property="BackgroundImageSource" Value="your_image.png" />
</Style>
</Application.Resources>
If you want all the pages in your project has the same background, you can create a BaseContentPage which have a background image or backgroundColor and then all other pages inherits from the BaseContentPage :
BaseContentPage:
public class BasePage : ContentPage
{
public BasePage()
{
this.BackgroundImageSource = "logo.jpg";
}
}
Other pages in your project:
public partial class Page1 : BasePage
{
public Page1()
{
InitializeComponent();
}
}
In Xaml:
<?xml version="1.0" encoding="utf-8" ?>
<xaminals:BasePage xmlns:xaminals="clr-namespace:Xaminals"
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="Xaminals.Page1">
<xaminals:BasePage.Content>
<StackLayout>
<Label Text="Welcome to Xamarin.Forms!"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
</StackLayout>
</xaminals:BasePage.Content>
</xaminals:BasePage>
Then all the pages will have the logo image as the background image.
The documentation says that I should use the page carousel for the place, this is a carousel view. But I do not understand how to do this.
I have three completely different pages. If earlier I could do like this. look how easy it is.
<CarouselPage 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"
xmlns:local="clr-namespace:test.Views"
x:Class="test.Corusel">
<CarouselPage.Children>
<local:Page1></local:Page1>
<local:Page2></local:Page2>
</CarouselPage.Children>
Now, when I try to make a look identical to the CarouselPage, I just have a white screen.
<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"
xmlns:local="clr-namespace:test.Views"
x:Class="test.Corusel">
<CarouselView>
<CarouselView.ItemTemplate>
<DataTemplate>
<StackLayout>
<local:View1></local:View1>
<local:View2></local:View2>
</StackLayout>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
</ContentPage>
People tell me that there should be an itemSource. Without itemSource, content will not be displayed. But as I understand it, itemSource does not allow you to make different layouts for data.
I don’t understand how I can make a copy of СarouselPage from СarouselView (or CollectionView) if:
My pages have different layouts!
To load content into different layouts, I use different functions!
In my knowledge what you are looking for is the DataTemplateSelector
Create a subclass of Selector with properties that hold the templates:
public class PersonDataTemplateSelector : DataTemplateSelector
{
public DataTemplate ValidTemplate { get; set; }
public DataTemplate InvalidTemplate { get; set; }
protected override DataTemplate OnSelectTemplate (object item, BindableObject container)
{
return ((Person)item).DateOfBirth.Year >= 1980 ? ValidTemplate : InvalidTemplate;
}
}
Add them to your resources:
<ContentPage.Resources>
<ResourceDictionary>
<DataTemplate x:Key="validPersonTemplate">
<ViewCell>
...
</ViewCell>
</DataTemplate>
<DataTemplate x:Key="invalidPersonTemplate">
<ViewCell>
...
</ViewCell>
</DataTemplate>
<local:PersonDataTemplateSelector x:Key="personDataTemplateSelector"
ValidTemplate="{StaticResource validPersonTemplate}"
InvalidTemplate="{StaticResource invalidPersonTemplate}" />
</ResourceDictionary>
</ContentPage.Resources>
Use them:
ItemTemplate="{StaticResource personDataTemplateSelector}"
For more information check the microsoft documents: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/templates/data-templates/selector
I have a template defined in App.Xaml
<ResourceDictionary>
<ControlTemplate x:Key="HomePageTemplate">
<Label Text="{Binding MyLabelText}"/>
</ControlTemplate>
</ResourceDictionary>
And I use it in my Home page
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:cv="clr-namespace:Xamarin.Forms;assembly=Xamarin.Forms.CarouselView"
xmlns:local="clr-namespace:App.Converters"
x:Class="App.Views.HomePage"
ControlTemplate="{StaticResource HomePageTemplate}">
</ContentPage>
I set the BindingContext of my Homepage in code behind.
Now shouldn't the ControlTemplate inherit the HomePage's BindingContext ? Because I thought that was the case but my Label doesn't keep the text from MyLabelText. What's the work around to work with Bindings in these templates ?
EDIT:
Using this option
<ResourceDictionary>
<ControlTemplate x:Key="HomePageTemplate">
<Label Text="{TemplateBinding Parent.BindingContext.MyLabelText}"/>
</ControlTemplate>
</ResourceDictionary>
Also does not work for me, because I use the ControlTemplatein the header of the HomePage and not inside it's body.
This works BUT IT'S NOT what I'm looking for:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:cv="clr-namespace:Xamarin.Forms;assembly=Xamarin.Forms.CarouselView"
xmlns:local="clr-namespace:App.Converters"
x:Class="App.Views.HomePage"
>
<ContentView ControlTemplate="{StaticResource HomePageTemplate}" />
</ContentPage>
With ControlTemplate controls the binding is slightly different. Have a look at these docs: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/templates/control-templates/template-binding
Assuming that the MyLabelText property is part of the BindingContext of the parent control your code could look like this:
<ResourceDictionary>
<ControlTemplate x:Key="HomePageTemplate">
<Label Text="{TemplateBinding Parent.BindingContext.MyLabelText }"/>
</ControlTemplate>
</ResourceDictionary>
App.xaml should have a BindingContext. Let's call it AppViewmodel, with a namespace vm (or any other key) defined at the top of App.xaml. This AppViewmodel can be bound to from within the ControlTemplate. In this example a button (placed in a stacklayout) is bound to a command named AppCommand, which resides in AppViewmodel. When this ControlTemplate is applied in a ContentPage, it binds to the ViewModel of App.xaml, not to the VM of that particular ContentPage. Perhaps the latter is also possible, for example by choosing the right settings for RelativeSource and AncestorType, but I haven't figured that out.
see also
<ControlTemplate x:Key="HomePageTemplate">
<StackLayout BindingContext="{Binding Source={RelativeSource TemplatedParent}}">
<Button
Command="{Binding Source={RelativeSource AncestorType={x:Type vm:AppViewModel}}, Path=AppCommand}"
/>
</StackLayout>
</ControlTemplate>
If anyone its interested, the way this works its just adding Path after TemplateBinding, specifying BindingContext on it and then the public var name:
<ResourceDictionary>
<ControlTemplate x:Key="HomePageTemplate">
<Label Text="{ TemplateBinding Path=BindingContext.MyLabelText }"/>
</ControlTemplate>
</ResourceDictionary>
I have changed the default color of the navigation bar by using these codes in app.xaml as I am unable to make it transparent on iOS devices:
<Style TargetType="NavigationPage">
<Setter Property="BarBackgroundColor" Value="#0a82b8" />
<Setter Property="BarTextColor" Value="#ffffff" />
</Style>
Now, there is an unnecessary navigation bar separator on iOS:
On Microsoft's official website, it says these codes can be helpful:
This platform-specific hides the separator line and shadow that is at
the bottom of the navigation bar on a NavigationPage. It's consumed in
XAML by setting the NavigationPage.HideNavigationBarSeparator bindable
property to false:
<NavigationPage ...
xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
ios:NavigationPage.HideNavigationBarSeparator="true">
</NavigationPage>
Alternatively, it can be consumed from C# using the fluent API:
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.iOSSpecific;
public class iOSTitleViewNavigationPageCS : Xamarin.Forms.NavigationPage
{
public iOSTitleViewNavigationPageCS()
{
On<iOS>().SetHideNavigationBarSeparator(true);
}
}
Source: Hiding the Navigation Bar Separator on a NavigationPage
The problem is that when I want to paste the ios:NavigationPage.HideNavigationBarSeparator="true" property into the <NavigationPage>tag, it gives this error:
No property, bindable property, or event found for 'HideNavigationBarSeparator', or mismatching type between value and property.
My full codes are:
<?xml version="1.0" encoding="utf-8"?>
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:My.App" x:Class="My.App.MainPage">
<MasterDetailPage.Master>
<ContentPage Title="Menu" BackgroundColor="#0a82b8" Icon="menu.png">
<StackLayout Orientation="Vertical">
<ListView x:Name="navigationDrawerList" RowHeight="55" SeparatorVisibility="None" BackgroundColor="#ffffff" ItemSelected="OnMenuItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<!-- Main design for our menu items -->
<StackLayout VerticalOptions="FillAndExpand" Orientation="Horizontal" Padding="20,10,0,10" Spacing="20">
<Label Text="{Binding Title}" FontSize="Large" VerticalOptions="Start" HorizontalOptions="CenterAndExpand" TextColor="#28DDFF" FontAttributes="Bold" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
</MasterDetailPage.Master>
<MasterDetailPage.Detail>
<NavigationPage xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
ios:NavigationPage.HideNavigationBarSeparator="true">
</NavigationPage>
</MasterDetailPage.Detail>
</MasterDetailPage>
Here is the tutorial which I followed for the MasterDetail navigation. The file which has <NavigationPage> tag is named as MainPage.xaml
You can use a custom renderer to hide that shadow:
[assembly: ExportRenderer(typeof(NavigationPage), typeof(CustomNavigationPage))]
namespace CustomNavigationPage.iOS
{
public class CustomNavigationPage : NavigationRenderer
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
NavigationBar.SetBackgroundImage(new UIKit.UIImage(), UIKit.UIBarMetrics.Default);
NavigationBar.ShadowImage = new UIKit.UIImage();
}
}
}
While you have accepted the answer, this one is more precise - you haven't followed the instructions that you have pasted from the site as you have ommited this line:
xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
Place UINavigationBar.Appearance.ShadowImage = new UIImage(); inside the public override bool FinishedLaunching(UIApplication app, NSDictionary options) method within AppDelegate.cs file. AppDelegate.cs resides within the iOS project of Xamarin.Forms
I have multiple ContentPage xaml files in my Xamarin project. I want to embed a shared piece of xaml into each ContentPage. There is nothing particularly special about the shared piece of xaml (it does't need to do anything platform specific). Shouldn't it be just as easy as embedding a tag in the xaml of the ContentPage to include the shared xaml file? Can someone point me in the right direction?
Thank you very much IdoT, It did work for me, but after adding some lines.
As this will help in making templates/custom controls/sub forms, easily added/shared across Xamarin.Forms.
Here is my full work based on your suggestion, so it can be used as is with others:
HeaderNavigationBar.xaml
<?xml version="1.0" encoding="utf-8" ?>
<StackLayout xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="App9.MVC.Views.HeaderNavigationBar"
Orientation="Horizontal"
HorizontalOptions="FillAndExpand"
Padding="10"
ackgroundColor="White">
<Button Text="Internal 1" />
<Button Text="Internal 2" />
</StackLayout>
As you can see, added:
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
and in the HeaderNavigationBar.cs, it was declared as StackLayout:
HeaderNavigationBar.cs
using Xamarin.Forms;
namespace App9.MVC.Views
{
public partial class HeaderNavigationBar : StackLayout
{
public HeaderNavigationBar()
{
InitializeComponent();
}
}
}
then for the page that will hold it/show it:
MainView.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"
xmlns:common="clr-namespace:App9.MVC.Views;assembly=App9"
x:Class="App9.MVC.Views.MainView">
<StackLayout Padding="0,0,0,20">
<common:HeaderNavigationBar>
<Button Text="External 1" />
</common:HeaderNavigationBar>
<Button Text="Test Button 1
x:Name="btnPage1"
Clicked="btnPage1_clicked" />
</StackLayout>
</ContentPage>
As you can notice, the namespace has the full path, in the MainView:
xmlns:common="clr-namespace:App9.MVC.Views;assembly=App9"
Also, you can notice that there is a button called External 1, this will also show with the
Internal buttons, as the control is a StackLayout, so it can handle adding more controls.
Screenshot:
Also for Page inside another Page:
https://github.com/twintechs/TwinTechsFormsLib
http://blog.twintechs.com/advanced-xamarin-forms-techniques-for-flexible-and-performant-cross-platform-apps-part-5-page-in-page-embedding
Again thanks goes to IdoT.
You can take the parent child of your ContentPage (for example, a StackLayout that wraps all the children), put it in an external xaml file,
and then include that component in each one of your ContentPages.
The external xaml file will be a StackLayout type, rather than a ContentPage.
Edit - added a code sample:
Let's add a header StackLayout: we add a code behind class:
public partial class HeaderNavigationBar
{
public HeaderNavigationBar()
{
InitializeComponent();
}
}
Then add the XAML code:
<StackLayout x:Class="HeaderNavigationBar"
Orientation="Horizontal"
HorizontalOptions="FillAndExpand"
Padding="10"
BackgroundColor="White">
<Image Source="burger_icon"
HorizontalOptions="StartAndExpand"
Aspect="AspectFit">
<Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding SlideNavigationDrawerCommand}" />
</Image.GestureRecognizers>
</Image>
</StackLayout>
And finally, in the page where you want to reuse your component - add this reference:<HeaderNavigationBar />.