I'm trying to create a Xamarin Forms user control containing a label and a placeholder where I can "nest" a child control.
I want the label on the left and the nested control on the right. They need to take a percentage of the available space i.e. the label should take one third and the nested control 2 thirds.
I'm trying to use a content presenter as a placeholder so I can use the user control like this
<userControls:PanelControl HeadingText="FIRST HEADING">
<DatePicker />
</userControls:PanelControl>
If I base the user control on a Stack Layout, the two controls appear in the correct position. The issue with using a Stack Layout is I can't implement percentage widths.
If I base the user control on a Grid, the nested control appears in the first column ovewriting the label. It looks like the Content Presenter does not work properly in a Grid.
Here is the Stack Layout based user control
<?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="BasicAppTemplate.UserControls.PanelControl"
Orientation="Horizontal">
<Label x:Name="HeadingLabel" VerticalOptions="Center"/>
<ContentPresenter/>
</StackLayout>
Here is the Grid based user control
<?xml version="1.0" encoding="UTF-8"?>
<Grid xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="BasicAppTemplate.UserControls.PanelGridControl">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<Label x:Name="HeadingLabel" VerticalOptions="Center" Grid.Column="0"/>
<StackLayout Grid.Column="1">
<ContentPresenter/>
</StackLayout>
</Grid>
Here is the page
<?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:userControls="clr-namespace:BasicAppTemplate.UserControls;assembly=BasicAppTemplate"
x:Class="BasicAppTemplate.Pages.MainPage">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<userControls:PanelControl HeadingText="FIRST HEADING">
<DatePicker />
</userControls:PanelControl>
<userControls:PanelGridControl HeadingText="SECOND HEADING" Grid.Row="1">
<DatePicker />
</userControls:PanelGridControl>
</Grid>
</ContentPage>
This what they both look like
Any ideas how to implement this? Is there another way I can create my nested user control?
Thanks to the pointer from DavidS the solution is to embed a ControlTemplate within the User Control
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="BasicAppTemplate.UserControls.PanelGridControl">
<ContentView.ControlTemplate>
<ControlTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<Label VerticalOptions="Center" Grid.Column="0" Text="{TemplateBinding HeadingText}" />
<ContentPresenter Grid.Column="1" />
</Grid>
</ControlTemplate>
</ContentView.ControlTemplate>
</ContentView>
Related
In an app I have two ContentView controls I am trying to compose within a top-level ContentPage. The first, ScaffoldView, contains some layout elements I want to have throughout the app:
<?xml version="1.0" encoding="UTF-8"?>
<ContentView 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="App.ScaffoldView">
<ContentView.Content>
<Grid
Margin="10,35,10,10"
VerticalOptions="FillAndExpand">
<Grid.RowDefinitions>...</Grid.RowDefinitions>
<!-- Awesome header stuff -->
<!-- I'd like the below to take given content -->
<ContentView
Grid.Row="..."
Content="{Binding Content}" />
<!-- Even more awesome footer stuff -->
</Grid>
</ContentView.Content>
</ContentView>
The second, InputsView, just has a few pairs of Label/Entry elements:
<?xml version="1.0" encoding="UTF-8"?>
<ContentView 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="App.InputsView">
<ContentView.Content>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Text="Label1"
FontSize="Medium"
VerticalTextAlignment="Center"
HorizontalTextAlignment="End" />
<Entry Grid.Column="1"
Text="Input1"
VerticalOptions="Center" />
<Label Grid.Row="1"
Text="Label2"
FontSize="Medium"
VerticalTextAlignment="Center"
HorizontalTextAlignment="End" />
<Entry Grid.Row="1"
Grid.Column="1"
Text="Input2"
VerticalOptions="Center" />
<Label Grid.Row="2"
Text="Label3"
FontSize="Medium"
VerticalTextAlignment="Center"
HorizontalTextAlignment="End" />
<Entry Grid.Row="2"
Grid.Column="1"
Text="Input3"
VerticalOptions="Center" />
</Grid>
</ContentView.Content>
</ContentView>
Finally, the top-level ContentPage:
<?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:controls="clr-namespace:App"
x:Class="App.MainPage">
<controls:ScaffoldView>
<controls:InputsView />
</controls:ScaffoldView>
</ContentPage>
Currently, all that shows is the InputsView. I suppose this is just because the entire Content of the MainPage is taken up with the ScaffoldView, and the entire Content of the ScaffoldView as defined in Scaffold.xaml is overridden by the <controls:InputsView /> tag.
Ideally, I'd like there to be some way of including <controls:InputsView /> inside the opening and closing <controls:ScaffoldView> tags as above, and it show this given content within the ScaffoldView's own content defined within Scaffold.xaml.
Is it possible to nest/mix Content this way, or will I need to define a custom property, e.g. ChildContent?
My code below creates what is shown in the picture below where the label's text is from an API I am calling. Also the drawing canvas is taken from https://github.com/xamarin/xamarin-forms-samples/tree/master/SkiaSharpForms/Demos/Demos/SkiaSharpFormsDemos. I was wondering how to make the drawing canvas more larger in height? Thank you.
<?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:skia="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
xmlns:tt="clr-namespace:TouchTracking"
x:Class="MathKumu.Pages.WorkPage">
<ContentPage.Content>
<StackLayout>
<Label Text="{Binding EquationString}" />
<Entry Placeholder="Put Answer Here" />
<Grid BackgroundColor="White">
<skia:SKCanvasView x:Name="canvasView"
PaintSurface="OnCanvasViewPaintSurface"/>
<Grid.Effects>
<tt:TouchEffect Capture="True"
TouchAction="OnTouchEffectAction" />
</Grid.Effects>
</Grid>
</StackLayout>
</ContentPage.Content>
</ContentPage>
Change your StackLayout to a Grid and specify that Row 2 has a Height of *. That will force Row 2 to consume all extra space.
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:skia="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
xmlns:tt="clr-namespace:TouchTracking"
x:Class="MathKumu.Pages.WorkPage">
<ContentPage.Content>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<Grid.RowDefinitions>
<Label Grid.Row="0" Text="{Binding EquationString}" />
<Entry Grid.Row="1" Placeholder="Put Answer Here" />
<Grid Grid.Row="2" BackgroundColor="White">
<skia:SKCanvasView x:Name="canvasView"
PaintSurface="OnCanvasViewPaintSurface"/>
<Grid.Effects>
<tt:TouchEffect Capture="True"
TouchAction="OnTouchEffectAction" />
</Grid.Effects>
</Grid>
</Grid>
</ContentPage.Content>
</ContentPage>
I am trying to get to this layout.
I got the red part correct but I am not able to position green box on top of the left part of the red box.
Green box needs to have same width as left part of the red part.
Green box has to be on the view from top to bottom.
This is my code so far. I am absolute xaml beginner so I have no clue if its even possible to do this kind of layout.
<?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="HOT_App.Views.ItemsPage"
Title="{Binding Title}"
x:Name="BrowseItemsPage">
<StackLayout>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="80"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"></ColumnDefinition>
</Grid.ColumnDefinitions>
<BoxView BackgroundColor="red" Grid.Row="0"></BoxView>
<BoxView BackgroundColor="red" Grid.Column="1"></BoxView>
<BoxView WidthRequest="300" BackgroundColor="green" Grid.Row="1"></BoxView>
<BoxView BackgroundColor="Aqua" Grid.Row="1" Grid.Column="1"></BoxView>
</Grid>
</StackLayout>
</ContentPage>
use RowSpan to make an element span multiple rows
<BoxView BackgroundColor="green" Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" />
I have a ContentPage with two ContentViews on it and i want to set the binding context for each of them each to their own respective ViewModel (this is my preferred soultion over one massive ViewModel for them combined)
MainPage
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage x:Class="MVVMFramework.VVMs.Main.MainPage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MVVMFramework"
xmlns:nav="clr-namespace:MVVMFramework.Navigation.NavigationHeader"
xmlns:vm="clr-namespace:MVVMFramework.VVMs.Main">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="20" />
<RowDefinition Height="200" />
</Grid.RowDefinitions>
//ContentView For Header
<ContentView Grid.Row="0"
HorizontalOptions="Start"
VerticalOptions="Start">
Content="{Binding NavHeader}"
<!--<ContentView.BindingContext>
<nav:NavigationHeaderViewModel />
</ContentView.BindingContext>-->
</ContentView>
//ContentView For Body of the app
<ContentView Grid.Row="1"
Content="{Binding DisplayedView}"
HorizontalOptions="Center"
VerticalOptions="Center">
<!--<ContentView.BindingContext>
<vm:MainPageViewModel />
</ContentView.BindingContext>-->
</ContentView>
</Grid>
</ContentPage>
When I uncomment both bindingcontext attributes the App compiles, and starts to run and then crashes when loading the MainPage.
Am i not implementing this correctly ?, is there another way to do it ?
Answer
You can specify the source for each view's binding using its BindingContext property like so:
BindingContext="{Binding Source = {Your Binding Source}}"
Sample App
Here's a sample app that shows how to reference multiple view models from the same ContentPage: https://github.com/brminnick/MultipleViewModelSample/
Code
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage x:Class="MVVMFramework.VVMs.Main.MainPage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MVVMFramework"
xmlns:nav="clr-namespace:MVVMFramework.Navigation.NavigationHeader"
xmlns:vm="clr-namespace:MVVMFramework.VVMs.Main">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="20" />
<RowDefinition Height="200" />
</Grid.RowDefinitions>
<ContentView
Grid.Row="0"
Content="{Binding NavHeader}"
HorizontalOptions="Start"
VerticalOptions="Start"
BindingContext="{Binding Source = {nav:NavigationHeaderViewModel}}"/>
<ContentView
Grid.Row="1"
Content="{Binding DisplayedView}"
HorizontalOptions="Center"
VerticalOptions="Center"
BindingContext="{Binding Source = {vm:MainPageViewModel}}"/>
</Grid>
</ContentPage>
I ma working on a cross platform app with Xamarin.Forms. I have a XAMl structure on my page as below:
<?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:local="clr-namespace:HeartRateMonitor;assembly=HeartRateMonitor"
x:Class="HeartRateMonitor.Pages.StartPage"
Title="Start Page">
<ContentPage.ToolbarItems>
</ContentPage.ToolbarItems>
<StackLayout>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
//more row defs
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Text="Percentage Fill:"
Grid.Row="2" Grid.Column="1" />
//Some other Items
<Button x:Name="NewDeviceButton" Icon="glyphish_31_circle_x.png"
Grid.Row="7" Grid.Column="0" /> //Causes app to crash
</Grid>
When I run this and deploy my app to an iPhone, the app crashes on startup. However, when I comment out the Button Object in the code, it deploys and runs fine.
What is wrong with that line and why is it causing the whole app to crash?
A Xamarin Forms Button does not have an Icon property. Use Image instead.
<Button x:Name="NewDeviceButton" Image="glyphish_31_circle_x.png"
Grid.Row="7" Grid.Column="0" />