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>
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 have below XAML which contains ContentView inside my main XAML.
I want to know how can I access the LabelPushNotificationPrice to change the Text?
<?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:SyncfusionBusyIndicator="clr-namespace:Syncfusion.SfBusyIndicator.XForms;assembly=Syncfusion.SfBusyIndicator.XForms"
x:Class="ZayedAlKhair.InitiativeDetails"
xmlns:SyncfusionPopup="clr-namespace:Syncfusion.XForms.PopupLayout;assembly=Syncfusion.SfPopupLayout.XForms"
Title="زايد الخير">
<ContentPage.Resources>
<ResourceDictionary>
<DataTemplate x:Key="PushNotificationsViewTemplate">
<ContentView BackgroundColor="White" x:Name="PushNotificationsContentView">
<StackLayout Padding="15">
<Label HorizontalTextAlignment="End" Text="هذه الخدمة تمكنكم من إرسال تنبيهات الهواتف الذكية لجميع مشتركي تطبيق زايد الخير وهي أفضل خدمة لتصل مبادرتكم لآلاف المشتركين" HeightRequest="90" WidthRequest="100" />
<Label x:Name="**LabelPushNotificationPrice**" HorizontalTextAlignment="End" Text="سعر الخدمة : 499 دولار" HeightRequest="30" WidthRequest="100" />
<Label HorizontalTextAlignment="End" Text="مدة الترويج : مرة واحدة لكل مبادرة" HeightRequest="30" WidthRequest="100" />
</StackLayout>
</ContentView>
</DataTemplate>
<DataTemplate x:Key="PromoteViewTemplate">
<ContentView BackgroundColor="White" x:Name="PromoteContentView">
<StackLayout Padding="15">
<Label HorizontalTextAlignment="End" Text="هذه الخدمة ستجعل مبادرتكم مميزة باللون الأحمر ودائما في أعلى القائمة ليتمكن كل مستخدمي التطبيق من التعرف عليها والتفاعل معها" HeightRequest="90" WidthRequest="100" />
<Label HorizontalTextAlignment="End" Text="سعر الخدمة : 99 دولار" HeightRequest="30" WidthRequest="100" />
<Label HorizontalTextAlignment="End" Text="مدة التمييز : 30 يوما" HeightRequest="30" WidthRequest="100" />
</StackLayout>
</ContentView>
</DataTemplate>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<Grid Padding="10" x:Name="GridInitiativeDetails">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
The preferred way is to use DataBindings, example:
<Label HorizontalTextAlignment="End" Text="{Binding LabelPushNotificationPrice}" />
This way you can seamlessly update the value of the Label bound to your ViewModel. The point is to separate UI layer from your BL layer and usually we use MVVM rather than MVC in Xamarin.Forms. The official documentation is nicely covering this topic and there are free e-books like Enterprise Application Patterns using Xamarin.Forms that I recommend to read additionally.
P.S.: Please note that setting a fixed Height & Width on UI controls may break your UX experience on screens with different sizes.
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>
I have a problem. I created a page that looks like this:
Now I want the content of the CollectionView to be centered. I already tried things to set on HorizontalOptions=Center, but no luck!
Here is the code of that part:
<StackLayout HorizontalOptions="CenterAndExpand">
<CollectionView ItemsSource="{Binding coinDataList}" ItemsLayout="HorizontalList" Margin="0" HorizontalOptions="CenterAndExpand" BackgroundColor="Red">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid RowSpacing="0" Margin="20,0,20,0" HorizontalOptions="CenterAndExpand" Padding="0">
<Grid.RowDefinitions>
<RowDefinition Height="20" />
<RowDefinition Height="5" />
<RowDefinition Height="20" />
<RowDefinition Height="10" />
<RowDefinition Height="20" />
</Grid.RowDefinitions>
<Label Grid.Row="0" VerticalOptions="CenterAndExpand" HorizontalOptions="Center" Text="{Binding Coin}" FontAttributes="Bold" TextColor="#00D8FF" FontSize="18"/>
<Label Grid.Row="2" VerticalOptions="CenterAndExpand" HorizontalOptions="Center" Text="{Binding Price, StringFormat='{0:F2}'}" TextColor="White" FontSize="18"/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
How can I do that?
You can achieve this by using BindableLayout in conjunction with the StackLayout with horizontal orientation. This will not be as performant as CollectionView, but from your UI, it looks like you will not be having a lot of items in your ItemSource collection, but you your need UI to be dynamic and evenly spaced and centered when there are fewer items. As the item list grows, the UI will look more like the horizontal list view.
So here is the minimal working XAML which you can modify to fit into your project. For sake of simplicity, I have added everything in the XAML (no code behind), so you can plug this XAML right into the content page and test it out!
<?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"
xmlns:generic="clr-namespace:System.Collections.Generic;assembly=netstandard"
mc:Ignorable="d"
x:Class="Playground.MainPage">
<ContentPage.Resources>
<ResourceDictionary>
<generic:List x:Key="SymbolNames" x:TypeArguments="x:String">
<x:String>BTC</x:String>
<x:String>LTC</x:String>
<x:String>ETH</x:String>
<x:String>OT1</x:String>
<x:String>OT2</x:String>
<x:String>OT3</x:String>
<x:String>OT4</x:String>
<x:String>OT5</x:String>
<x:String>OT6</x:String>
</generic:List>
</ResourceDictionary>
</ContentPage.Resources>
<ScrollView Orientation="Horizontal" HeightRequest="60" VerticalOptions="Start">
<StackLayout BindableLayout.ItemsSource="{Binding Source={StaticResource SymbolNames}}" Orientation="Horizontal">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Label Text="{Binding}" HorizontalOptions="CenterAndExpand" VerticalOptions="Center" Margin="10"/>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</ScrollView>
</ContentPage>
UI when 3 Items:
UI When multiple overflowing items: