I am using Xamaring form and I would like to transform my Xaml code into c# code.
I have manage to the XAML code but I do know how to do the c# code
here is my code :
<StackLayout Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" x:Name="GridRectangle" >
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Tapped="OnImageNewsTappedGridRectangle"/>
</StackLayout.GestureRecognizers>
<AbsoluteLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<Image x:Name="GridRectangleImage" Source="" Aspect="AspectFill" AbsoluteLayout.LayoutBounds="1,1,1,1" AbsoluteLayout.LayoutFlags="All"/>
<AbsoluteLayout AbsoluteLayout.LayoutBounds="1,1,1,1" AbsoluteLayout.LayoutFlags="All" BackgroundColor="#66000000" >
<StackLayout Orientation="Vertical" BackgroundColor="Transparent" AbsoluteLayout.LayoutFlags="All" AbsoluteLayout.LayoutBounds="1,1,1,1" >
<StackLayout VerticalOptions="StartAndExpand" HorizontalOptions="StartAndExpand" Padding="3">
<Label x:Name="GridRectangleTitle" Text="" FontSize="Medium" TextColor="White" FontAttributes="Bold"></Label>
</StackLayout>
<StackLayout VerticalOptions="EndAndExpand" HorizontalOptions="EndAndExpand" Padding="3">
<Label x:Name="GridRectangleProviderAndDate" Text="" TextColor="White" FontSize="Small" FontAttributes="Italic"></Label>
</StackLayout>
</StackLayout>
</AbsoluteLayout>
</AbsoluteLayout>
</StackLayout>
Here is the TapGestureRecognizer function:
void OnImageNewsTappedGridRectangle(object sender, EventArgs args) {
OnArticleTapped(GridRectangleUrl);
}
Thanks for your help
Here is a sample of C# and XAML of the same page.
C#
public class MyPage : ContentPage
{
Button loginButton;
StackLayout layout;
public MyPage()
{
layout = new StackLayout
{
Children =
{
new Label { Text = "Please log in" },
new Label { Text = "Username", TextColor = Color.Black },
new Entry (),
new Label { Text = "Password", TextColor = Color.Black },
new Entry { IsPassword = true },
}
};
loginButton = new Button { Text = "Login" };
layout.Children.Add(loginButton);
Content = layout;
loginButton.Clicked += (sender, e) =>
{
Debug.WriteLine("Clicked !");
};
}
}
XAML Sample
<?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="Sample.MyPage">
<ContentPage.Content>
<StackLayout>
<Label Text="Please log in" />
<Label Text="Username" TextColor="Black" />
<Entry />
<Label Text="Password" TextColor="Black" />
<Entry IsPassword="true" />
<Button Text="Log in" Clicked="LoginButton_Clicked" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
I would take some time and learn Xamarin and the benefits of using XAML for the UI and behavior logic in C# code. One huge benefit is the preview support built in to Visual Studio. I think you will see (and other will agree) that this separation of concerns is the preferred way to develop.
There are some code to transform your code from xaml to C#, you can take a look:
This is your xaml code:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackLayout
x:Name="GridRectangle"
Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="2">
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Tapped="OnImageNewsTappedGridRectangle" />
</StackLayout.GestureRecognizers>
<AbsoluteLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<Image
x:Name="GridRectangleImage"
AbsoluteLayout.LayoutBounds="1,1,1,1"
AbsoluteLayout.LayoutFlags="All"
Aspect="AspectFill"
Source="a11.jpg" />
<AbsoluteLayout
AbsoluteLayout.LayoutBounds="1,1,1,1"
AbsoluteLayout.LayoutFlags="All"
BackgroundColor="#66000000">
<StackLayout
AbsoluteLayout.LayoutBounds="1,1,1,1"
AbsoluteLayout.LayoutFlags="All"
BackgroundColor="Transparent"
Orientation="Vertical">
<StackLayout
Padding="3"
HorizontalOptions="StartAndExpand"
VerticalOptions="StartAndExpand">
<Label
x:Name="GridRectangleTitle"
FontAttributes="Bold"
FontSize="Medium"
Text="this is stacklayout1"
TextColor="White" />
</StackLayout>
<StackLayout
Padding="3"
HorizontalOptions="EndAndExpand"
VerticalOptions="EndAndExpand">
<Label
x:Name="GridRectangleProviderAndDate"
FontAttributes="Italic"
FontSize="Small"
Text="this is stacklayout2"
TextColor="White" />
</StackLayout>
</StackLayout>
</AbsoluteLayout>
</AbsoluteLayout>
</StackLayout>
</Grid>
This is your corresponding C # in the page constructor, you can try.
Grid grid = new Grid();
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
var GridRectangle = new StackLayout();
var tapGestureRecognizer = new TapGestureRecognizer();
tapGestureRecognizer.Tapped += (s, e) =>
{
// handle the tap
};
GridRectangle.GestureRecognizers.Add(tapGestureRecognizer);
var layout = new AbsoluteLayout() { HorizontalOptions = LayoutOptions.FillAndExpand, VerticalOptions = LayoutOptions.FillAndExpand };
var GridRectangleImage = new Image() { Source = "a11.jpg", Aspect = Aspect.AspectFill };
AbsoluteLayout.SetLayoutBounds(GridRectangleImage, new Rectangle(1, 1, 1, 1));
AbsoluteLayout.SetLayoutFlags(GridRectangleImage, AbsoluteLayoutFlags.All);
var layout2 = new AbsoluteLayout() { BackgroundColor = Color.FromHex("#66000000") };
AbsoluteLayout.SetLayoutBounds(layout2, new Rectangle(1, 1, 1, 1));
AbsoluteLayout.SetLayoutFlags(layout2, AbsoluteLayoutFlags.All);
var stacklayout1 = new StackLayout() { Orientation = StackOrientation.Vertical, BackgroundColor = Color.Transparent };
AbsoluteLayout.SetLayoutBounds(stacklayout1, new Rectangle(1, 1, 1, 1));
AbsoluteLayout.SetLayoutFlags(stacklayout1, AbsoluteLayoutFlags.All);
var stacklayout2 = new StackLayout() { HorizontalOptions = LayoutOptions.StartAndExpand, VerticalOptions = LayoutOptions.StartAndExpand, Padding = 3 };
var GridRectangleTitle = new Label() { Text = "this is stackalyout1", FontSize = Device.GetNamedSize(NamedSize.Medium, typeof(Label)), FontAttributes = FontAttributes.Bold, TextColor = Color.White };
stacklayout2.Children.Add(GridRectangleTitle);
var stacklayout3 = new StackLayout() { HorizontalOptions = LayoutOptions.EndAndExpand, VerticalOptions = LayoutOptions.EndAndExpand, Padding = 3 };
var GridRectangleProviderAndDate = new Label() { Text = "this is stackalyout2", FontSize = Device.GetNamedSize(NamedSize.Small, typeof(Label)), FontAttributes = FontAttributes.Italic, TextColor = Color.White };
stacklayout3.Children.Add(GridRectangleProviderAndDate);
stacklayout1.Children.Add(stacklayout2);
stacklayout1.Children.Add(stacklayout3);
layout2.Children.Add(stacklayout1);
layout.Children.Add(GridRectangleImage);
layout.Children.Add(layout2);
GridRectangle.Children.Add(layout);
grid.Children.Add(GridRectangle, 0, 0);
Grid.SetColumnSpan(GridRectangle, 2);
this.Content = grid;
Related
I have been stuck with this issue for quite sometime now. It might be quite simple for you guys.
I have a collection view which has its item source that shows an observable collection. It shows messages from users when the app starts and then as a new message comes, I want to add the new message as the 1st element in the collectionview but it gets distorted and removes the prior items (only from the UI and not the actual observable collection data) and only shows 1 item. And when I navigate to other page and come back it shows correctly. Could someone please help me with this.
Xaml
<CollectionView Grid.Row="1" x:Name="myMessagesCV" SelectionMode="Single" SelectionChanged="MyMessagesCV_SelectionChanged" RemainingItemsThresholdReached="MyMessagesCV_RemainingItemsThresholdReached" RemainingItemsThreshold="5">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="8, 8, 8, 0">
<Grid Padding="0" ColumnSpacing="0" RowSpacing="0" Margin="2">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ffimageloading:CachedImage x:Name="userImage" Source="{Binding userImage}" Aspect="AspectFill" HeightRequest="75" Grid.Row="0" Grid.Column="0" CacheType="All" DownsampleToViewSize="True">
<ffimageloading:CachedImage.Transformations>
<transformations:CircleTransformation/>
</ffimageloading:CachedImage.Transformations>
</ffimageloading:CachedImage>
<Grid Grid.Row="0" Grid.Column="1" Padding="5">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label Padding="10, 0, 0, 5" Text="{Binding userName}" LineBreakMode="TailTruncation" TextColor="Black" FontSize="Medium" Grid.Row="0" Grid.Column="0"/>
<Label Padding="10, 0, 0, 5" Text="{Binding message}" FontAttributes="{Binding newMessage}" FontSize="Small" TextColor="Black" Grid.Row="1" Grid.Column="0" HorizontalOptions="StartAndExpand" />
<Image Grid.Row="0" Grid.Column="1" Grid.RowSpan="2" Source="dot.png" Aspect="AspectFill" WidthRequest="10" IsVisible="{Binding IsNewMessage}" HorizontalOptions="Center" VerticalOptions="Center"/>
</Grid>
<BoxView BackgroundColor="LightGray" HeightRequest="1" Grid.Row="1" Grid.Column="1"/>
</Grid>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Code Behind Page
public ObservableCollection<Messages> MyMessagesList = new ObservableCollection<Messages>();
public async void GetMyMessages()
{
if (IsBusy)
return;
IsBusy = true;
var messages = await FirebaseDataHelper.GetMyMessages(uid);
var allmyMessages = await Task.WhenAll(FirebaseDataHelper.GetUserMessagesDetail(messages));
myunreadmsg = 0;
allmyMessagesCount = messages.Count;
IsSubscribe = false;
foreach (var message in allmyMessages)
{
if (message.Count > 0)
{
for (int i = 0; i < message.Count; i++)
{
if (message[i].status == "Delivered" && message[i].senderId != uid)
{
message[i].newMessage = FontAttributes.Bold;
message[i].IsNewMessage = true;
myunreadmsg++;
}
if (!MyMessagesList.Any(m => m.otheruserId == message[i].otheruserId) && message[i].message != null)
MyMessagesList.Add(message[i]);
}
}
}
myMessagesCV.ItemsSource = MyMessagesList;
}
public void GetMyNewMessages(Messages messageData)
{
IsSubscribe = false;
myunreadmsg = 0;
Messages newMessageData = new Messages();
if (messageData.status == "Delivered" && messageData.senderId != uid)
{
newMessageData.newMessage = FontAttributes.Bold;
newMessageData.IsNewMessage = true;
newMessageData.otheruserId = messageData.otheruserId;
newMessageData.senderId = messageData.senderId;
newMessageData.sellerId = messageData.sellerId;
myunreadmsg++;
}
else
{
newMessageData.newMessage = FontAttributes.None;
}
for (int i = 0; i < MyMessagesList.Count; i++)
{
if (MyMessagesList[i].otheruserId == messageData.otheruserId)
{
if (i == 0)
{
MyMessagesList[i].message = messageData.message;
if (myunreadmsg > 0)
{
MyMessagesList[i].IsNewMessage = true;
MyMessagesList[i].newMessage = FontAttributes.Bold;
}
break;
}
else
{
newMessageData.userName = MyMessagesList[i].userName;
newMessageData.userImage = MyMessagesList[i].userImage;
newMessageData.message = messageData.message;
newMessageData.time = messageData.time;
newMessageData.messageId = messageData.messageId;
MyMessagesList.Remove(MyMessagesList[i]);
MyMessagesList.Insert(0, newMessageData);
break;
}
}
}
myMessagesCV.ItemsSource = MyMessagesList;
}
Thank you guys. Hope I can solve this.
When your new message arrives, don't set ItemSource again like you do it in your GetMyNewMessages method:
myMessagesCV.ItemsSource = MyMessagesList;
Just insert your new message into MyMessagesList ObservableCollection.
MyMessagesList.Insert(0, newMessageData);
I made a simple project where it is demonstrated.
Here is xaml:
<ContentPage
x:Class="Search.MainPage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
BackgroundColor="White">
<Grid Margin="15">
<CollectionView
x:Name="CollectionView"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<CollectionView.ItemTemplate>
<DataTemplate>
<Label Text="{Binding}" TextColor="Red" />
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</Grid>
</ContentPage>
And here is code behind of this page:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
public ObservableCollection<int> Data { get; set; } = new ObservableCollection<int>(Enumerable.Range(1, 10));
protected override void OnAppearing()
{
base.OnAppearing();
Device.StartTimer(TimeSpan.FromSeconds(3), () =>
{
Data.Insert(0, new Random().Next(1, 1000));
return true;
});
CollectionView.ItemsSource = Data;
}
}
I need something like this:
And I have this right now:
XAML:
<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="PetCare.Client.View.Forgot.ForgotPasswordView">
<ContentPage.Content>
<Grid RowSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="*" ></RowDefinition>
<RowDefinition Height="*" ></RowDefinition>
<RowDefinition Height="*" ></RowDefinition>
<RowDefinition Height="*" ></RowDefinition>
<RowDefinition Height="*" ></RowDefinition>
<RowDefinition Height="*" ></RowDefinition>
<RowDefinition Height="*" ></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" ></ColumnDefinition>
<ColumnDefinition Width="auto" ></ColumnDefinition>
<ColumnDefinition Width="2*" ></ColumnDefinition>
</Grid.ColumnDefinitions>
<StackLayout Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="3"
x:Name="BackgroundTop">
</StackLayout>
<Image Grid.Row="0"
Grid.Column="1"
Grid.RowSpan="2"
x:Name="Icon"/>
<StackLayout Grid.Row="2"
Grid.Column="0"
Grid.ColumnSpan="3"
Grid.RowSpan="4"
x:Name="BackgroundBot"
Spacing="0">
<Label Grid.Row="2"
Grid.Column="1"
x:Name="TextTitleLable"
/>
<StackLayout Grid.Row="3"
Grid.Column="1"
BackgroundColor="Red"
x:Name="BackgroundImage"
Spacing="0">
<Image x:Name="Phone"/>
</StackLayout>
<StackLayout Grid.Row="3"
Grid.Column="1"
BackgroundColor="Blue"
x:Name="BackgroundTextDescription"
Spacing="0">
<Label x:Name="TextDescription"></Label>
</StackLayout>
<StackLayout Grid.Row="4"
Grid.RowSpan="2"
x:Name="BackgroundInputNavigation">
<Entry x:Name="InputUser" />
<Label x:Name="ErrorMessage"/>
<Label x:Name="OtherOption"/>
</StackLayout>
</StackLayout>
<Button Grid.Row="8"
Grid.Column="1"
x:Name="BtnContinue"
Clicked="ClickedBtnContinue"/>
</Grid>
</ContentPage.Content>
</ContentPage>
C#:
//BackgrouTextndInputNavigation.
public ForgotPasswordView()
{
InitializeComponent();
NavigationPage.SetHasNavigationBar(this, false);
SetColorsApp();
SetBtnContinueProperties();
SetTextTitleLableProperties();
SetIconProperties();
SetBackgroundTopProperties();
SetBackgroundBotProperties();
SetInputUserProperties();
SetOtherOptionProperties();
SetErrorMessageProperties();
SetPhoneProperties();
SetTextDescriptionProperties();
SetBackgroundImageProperties();
SetBackgroundTextDescriptionProperties();
}
private void SetBackgroundTextDescriptionProperties()
{
BackgroundTextDescription.Orientation = StackOrientation.Horizontal;
BackgroundTextDescription.HorizontalOptions = LayoutOptions.End;
BackgroundTextDescription.VerticalOptions = LayoutOptions.Center;
}
private void SetBackgroundImageProperties()
{
BackgroundImage.Orientation = StackOrientation.Horizontal;
BackgroundImage.HorizontalOptions = LayoutOptions.Start;
BackgroundImage.VerticalOptions = LayoutOptions.Center;
}
private void SetTextDescriptionProperties()
{
Label textPhoneNumber = new Label();
textPhoneNumber.Text = "XXXXX-XX89";
textPhoneNumber.TextColor = Color.FromHex(ColorsApp.ColorAppWarning);
textPhoneNumber.FontSize = 18;
string Text = "Foi enviada uma mensagem\ncom Código de Verificação\npara o Telefone "+ textPhoneNumber.Text+ "\ncadastrado em sua conta.\nInforme este Código para\nprosseguir.".Replace("\n", System.Environment.NewLine);
TextDescription.Text = Text;
TextDescription.FontSize = 18;
TextDescription.HorizontalTextAlignment = TextAlignment.End;
TextDescription.VerticalOptions = LayoutOptions.Center;
}
private void SetPhoneProperties()
{
Phone.Source = ImageSource.FromFile("phone.png");
Phone.HorizontalOptions = LayoutOptions.Start;
Phone.VerticalOptions = LayoutOptions.Center;
Phone.HeightRequest = 110;
}
private void SetErrorMessageProperties()
{
ErrorMessage.FontAttributes = FontAttributes.Bold;
ErrorMessage.Margin = new Thickness(0, 0, 0, 30);
}
private void SetOtherOptionProperties()
{
var tap = new TapGestureRecognizer();
tap.Tapped += async (s, e) => await Navigation.PushAsync(new OtherOptionResetPasswordView());
OtherOption.Text = "Usar outra opção de verificação";
OtherOption.FontSize = 18;
OtherOption.GestureRecognizers.Add(tap);
OtherOption.TextColor = Color.FromHex(ColorsApp.ColorAppPrimary);
tap = null;
}
private void SetInputUserProperties()
{
InputUser.Placeholder = "Inserir o Código";
InputUser.Margin = new Thickness(0, 20, 0, 0);
}
private void SetBackgroundBotProperties()
{
BackgroundBot.Padding = 30;
BackgroundBot.HeightRequest = 300;
BackgroundBot.HorizontalOptions = LayoutOptions.FillAndExpand;
BackgroundBot.VerticalOptions = LayoutOptions.FillAndExpand;
}
private void SetBackgroundTopProperties()
{
BackgroundTop.BackgroundColor = Color.FromHex(ColorsApp.ColorAppThemePrimary);
BackgroundTop.HorizontalOptions = LayoutOptions.FillAndExpand;
BackgroundTop.VerticalOptions = LayoutOptions.FillAndExpand;
BackgroundTop.Padding = 10;
}
private void SetIconProperties()
{
Icon.Source = ImageSource.FromFile("smartphone.png");
Icon.HorizontalOptions = LayoutOptions.Center;
Icon.VerticalOptions = LayoutOptions.Center;
}
private void SetTextTitleLableProperties()
{
TextTitleLable.HorizontalTextAlignment = TextAlignment.Start;
TextTitleLable.VerticalTextAlignment = TextAlignment.Start;
TextTitleLable.Text = "Verificar Identidade";
TextTitleLable.FontSize = 28;
TextTitleLable.TextColor = Color.FromHex(ColorsApp.ColorAppDark);
}
private void SetBtnContinueProperties()
{
BtnContinue.BackgroundColor = Color.FromHex(ColorsApp.ColorAppThemePrimary);
BtnContinue.VerticalOptions = LayoutOptions.End;
BtnContinue.HorizontalOptions = LayoutOptions.End;
BtnContinue.TextColor = Color.White;
BtnContinue.Padding = new Thickness(3);
BtnContinue.Margin = new Thickness(0, 0, 30, 30);
BtnContinue.Text = "Continuar";
BtnContinue.FontSize = 22;
BtnContinue.WidthRequest = 140;
}
private void SetColorsApp()
{
BackgroundBot.BackgroundColor = Color.FromHex(ColorsApp.ColorAppThemeDefault);
}
private async void ClickedBtnContinue(object sender, EventArgs e)
{
await Navigation.PushAsync(new ResetPasswordView());
}
I need two things: put the phone number in another color; and place the image next to the label.
I am very beginner, so I ask for some code along with the explanation. Please
It appears that even if the components are oriented horizontally, they
cannot stand side by side. I tried to put both in the same stack
layout but the stack layout height is based on the image, leaving one
or two lines of text hidden
Being honest with you, your Grid is a mess XD
First of all, you should be aware that by using Grid you should be able to get rid of most (if not all) of your Stacklayouts. Please take a look at the great docu that Xamarin has on Grid and many other topics :D
Next i share with you a Grid that i worked out to display what you want (notice the lack of Stacklayout!):
<Grid Padding="20" RowSpacing="70"
BackgroundColor="White">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2"
Text="Verificar Identidade"
FontSize="30"/>
<Image Grid.Row="1" Grid.Column="0"
Source="TelefonImage"
WidthRequest="100"/>
<Label Grid.Row="1" Grid.Column="1"
FontSize="Medium"
HorizontalTextAlignment="End">
<Label.FormattedText>
<FormattedString>
<Span Text="Foi enviada uma mensagem com Código de Verificação para o Telefone "/>
<Span Text="XXXXX-XX89"
TextColor="Orange"/>
<Span Text=" cadastrado em sua conta. Informe este Código para prosseguir."/>
</FormattedString>
</Label.FormattedText>
</Label>
</Grid>
On my side this looks like:
Also take note of what #Jason said in the comment: "everything you're doing in C# could be included in your XAML" (and that mean all the property setting).
I hope that will get you going!
Edit 1
I was able to quickly achieve the result in the image above by using the Hot Reload in Xamarin.Forms: play with it!
I am trying to create a menu page where I need to keep a button on screen even if a scroll, like button stops at the edge of the screen, and I have this layout in XML but I needed it in code behind to add some frame dynamic. This is what I made but it's not show up the same. Any suggestions please?
<Grid RowSpacing="0" ColumnSpacing="0">
<Grid.Margin>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS" Value="0,20,0,0" />
</OnPlatform>
</Grid.Margin>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label Text="FIXED HEADER DEMO" Margin="12" Grid.Row="0" FontSize="14" />
<Grid x:Name="ContentGrid" RowSpacing="0" ColumnSpacing="0" Grid.Row="1">
<ScrollView x:Name="TheScroll">
<Grid RowSpacing="0" ColumnSpacing="0">
<Grid.RowDefinitions>
<RowDefinition x:Name="ImageRow" Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Image x:Name="BearImage" Source="bear.jpg"
Aspect="AspectFill"
Grid.Row="0" />
<Label LineBreakMode="WordWrap"
Margin="12,5,12,5"
Grid.Row="1">
Text="abc"
</Label>
</Grid>
</ScrollView>
<Label x:Name="TitleText"
Text="Bear found in the wild!"
TextColor="White"
BackgroundColor="#FF264778"
HeightRequest="40"
VerticalOptions="Start" VerticalTextAlignment="Center"
HorizontalTextAlignment="Center" />
</Grid>
</Grid>
My code behind
public void PageConstructor()
{
Grid thirdG = new Grid
{
RowDefinitions =
{
new RowDefinition { Height = new GridLength(1,GridUnitType.Auto) },
new RowDefinition { Height = new GridLength(1,GridUnitType.Star) },
},
};
var image1 = new Image
{
Source = "bear.jpg",
};
var labeltext = new Label
{
LineBreakMode = LineBreakMode.WordWrap,
Text = msg + msg2 + msg3,
};
thirdG.Children.Add(image1, 0, 0);
thirdG.Children.Add(labeltext, 0, 1);
Grid secondG = new Grid
{
};
SecondTitle= new Label { Text = "Second title text", TextColor = Color.Black };
scrollV = new ScrollView { Content = thirdG };
secondG.Children.Add(SecondTitle);
secondG.Children.AddVertical(scrollV);
Grid firstG = new Grid
{
RowDefinitions =
{
new RowDefinition { Height = new GridLength(1,GridUnitType.Auto) },
new RowDefinition { Height = new GridLength(1,GridUnitType.Star) },
},
};
firstG.Children.Add(new Label { Text = "Title" }, 0, 0);
firstG.Children.Add(secondG, 0, 1);
Content = firstG;
}
According to your code, I find you use ScrollView in Grid, it will be covered by label TitleText, so I suggest you can put scrollview outside the grid
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label
Grid.Row="0"
Margin="12"
FontSize="14"
Text="FIXED HEADER DEMO" />
<ScrollView Grid.Row="1">
<Grid x:Name="ContentGrid">
<Grid.RowDefinitions>
<RowDefinition x:Name="ImageRow" Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Image
x:Name="BearImage"
Grid.Row="0"
HeightRequest="50"
Source="a11.jpg"
WidthRequest="50" />
<Label
Grid.Row="1"
Margin="12,5,12,5"
LineBreakMode="WordWrap">
Text="abc"
</Label>
<Label
x:Name="TitleText"
BackgroundColor="#FF264778"
HeightRequest="40"
HorizontalTextAlignment="Center"
Text="Bear found in the wild!"
TextColor="White"
VerticalOptions="Start"
VerticalTextAlignment="Center" />
</Grid>
</ScrollView>
</Grid>
Same effect in code behind:
public Page3()
{
InitializeComponent();
var image1 = new Image
{
Source = "a11.jpg",WidthRequest=70,HeightRequest=70
};
var label1 = new Label
{
Text = "abc"
};
var label2 = new Label
{
Text = "Bear found in the wild!",HeightRequest=20,VerticalTextAlignment=TextAlignment.Center,HorizontalTextAlignment=TextAlignment.Center
};
Grid secondG = new Grid
{
RowDefinitions =
{
new RowDefinition { Height = new GridLength(1,GridUnitType.Auto) },
new RowDefinition { Height = new GridLength(1,GridUnitType.Star) },
},
};
var scrollV = new ScrollView { Content = secondG };
secondG.Children.Add(image1,0,0);
secondG.Children.Add(label1,0,1);
secondG.Children.Add(label2);
Grid firstG = new Grid
{
RowDefinitions =
{
new RowDefinition { Height = new GridLength(1,GridUnitType.Auto) },
new RowDefinition { Height = new GridLength(1,GridUnitType.Star) },
},
};
var labeltext = new Label
{
LineBreakMode = LineBreakMode.WordWrap,FontSize=14,
Text = "FIXED HEADER DEMO"
};
firstG.Children.Add(labeltext, 0, 0);
firstG.Children.Add(scrollV, 0, 1);
Content = firstG;
}
}
Desired Result :
I have a list of objects that contains the Title of every section in the menu and in this list I have the list of images and other information
I've been strugeling on how to display them properly
my xaml :
<ContentPage.Content>
<TableView Intent="Form">
<TableRoot>
<TableSection Title="Getting Started">
<ViewCell>
<Grid VerticalOptions="FillAndExpand" Padding = "20, 0" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" ></RowDefinition>
<RowDefinition Height="Auto" ></RowDefinition>
</Grid.RowDefinitions>
<StackLayout Grid.Row="0" x:Name="Titre" Orientation="Horizontal">
</StackLayout>
<ScrollView Grid.Row="1">
<StackLayout
Padding="0"
x:Name="Image">
</StackLayout>
</ScrollView>
</Grid>
</ViewCell>
</TableSection>
</TableRoot>
</TableView>
</ContentPage.Content>
The C# Method :
private void PopulateProductsLists(List<PlanDefinition> listArticles)
{
for (var i = 0; i < listArticles.Count; i++)
{
//Display Title
Titre.Children.Add((new Label { Text = listArticles[i].Name, Style = Device.Styles.TitleStyle, FontAttributes = FontAttributes.Bold, TextColor = Color.White }));
//Display Images from listArticles[i].ArticlesAvailable
for (int j= 0; j < listArticles[i].ArticlesAvailable.Count; j++)
{
listArticles[i].ArticlesAvailable[j].ImageProduit = "https://fit-plans.com/" + listArticles[i].ArticlesAvailable[j].UrlSmallImage;
Image image = new Image();
image.Source = ImageSource.FromUri(new Uri(listArticles[i].ArticlesAvailable[j].ImageProduit));
Image.Children.Add(image);
}
What I am droing wrong?
First of all here were my mistakes :
1- Not using a scrollable view
2- Using different stack layouts
The remedy to my issue :
<!----Scrollable view MUST be used otherwide data simply won't appear --->
<ScrollView
Grid.Column="0"
Grid.Row="1">
<Grid
RowSpacing="3"
x:Name="MyGrid"
ClassId="myGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<StackLayout VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand"
x:Name="ProduitsLayout">
<!----Products will be displayed here --->
</StackLayout>
</Grid>
</ScrollView>
And in the code behind :
private void PopulateProductsLists(List<PlanDefinition> listArticles)
{
int labelIndex = 0;
int count = 0;
for (var i = 0; i < listArticles.Count; i++)
{
//Calling a view to display data
item = new PlanOrderTemplate();
var lastHeight = "100";
var y = 0;
int column = 1;
var productTapGestureRecognizer = new TapGestureRecognizer();
//Add label in the stack layout
ProduitsLayout.Children.Add((new Label
{
Text = listArticles[i].Name,
Style = Device.Styles.TitleStyle,
FontAttributes = FontAttributes.Bold,
TextColor = Color.Black
}));
for (int j = 0; j < listArticles[i].ArticlesAvailable.Count; j++)
{
productTapGestureRecognizer.Tapped += OnProductTapped;
item = new PlanOrderTemplate();
listArticles[i].ArticlesAvailable[j].ThumbnailHeight = lastHeight;
//Applying binding to the view in order to display data
item.BindingContext = listArticles[i].ArticlesAvailable[j];
item.GestureRecognizers.Add(productTapGestureRecognizer);
//This is mandatory you need to call the add the view page to the stack layout
ProduitsLayout.Children.Add(item);
}
}
}
Now as for the view page I'm talking about : ProduitsLayout.xaml
Configure the image I want to load with a stepper
<StackLayout Orientation="Vertical"
Spacing="1">
<ffimageloading:CachedImage
FadeAnimationEnabled="true"
Source="{Binding ImageProduit}"
HeightRequest="{Binding ThumbnailHeight}"
Aspect="AspectFill"/>
<Label x:Name="lbldisp" Text="1" VerticalOptions="Center" HorizontalOptions="Center"></Label>
<Stepper Minimum="0" Maximum="10" Increment="1" HorizontalOptions="FillAndExpand" VerticalOptions="CenterAndExpand" ValueChanged="OnValueChanged" />
</StackLayout>
I have followed Gusman's advice and I positioned by layout in this order:
->StackLayout, VerticalOptions=FillAndExpand
->ScrollView, VerticalOptions=FillAndExpand
->RelativeLayout
->StackLayout
->StackLayout
->Button, VerticalOptions=EndAndExpand
Where I want my Button to be fixed on the bottom of my device view when scrolling throughout the whole layout. However, the view does not show the redeem button nor the full scroll bar. I'm not sure why those two elements are not displaying on the view.
How can I fix button on the bottom of the view when scrolling vertically on device?
Here's my latest code:
public StackLayout OffersSlideViewCarouselChild(Offer offer)
{
Image productImage = new Image
{
Source = ImageSource.FromUri(new Uri(offer.Image.Replace("https://", "http://"))),
HorizontalOptions = LayoutOptions.CenterAndExpand,
VerticalOptions = LayoutOptions.CenterAndExpand,
HeightRequest = 300,
WidthRequest = 300,
Aspect = Aspect.AspectFit
};
var topStackLayout = new StackLayout
{
HorizontalOptions = LayoutOptions.CenterAndExpand,
VerticalOptions = LayoutOptions.Center,
};
topStackLayout.Children.Add(productImage);
StackLayout contentStackLayout = new StackLayout
{
Padding = new Thickness(16, 16, 16, 10),
Orientation = StackOrientation.Vertical,
HorizontalOptions = LayoutOptions.FillAndExpand,
};
var savedBtn = SavedButtonLayout(offer.IsSelected, offer.Id);
var redeemBtn = RedeemBtnLayout(offer.Id);
var timeRemainingLabel = TimeRemainingLayout(offer, offer.Id);
contentStackLayout.Children.Add(new UILabel(16) {
Text = offer.ProductName,
TextColor = ColorHelper.FromHex(CoreTheme.COLOR_OFFERCELL_PRODUCT_TEXT),
FontFamily = CoreTheme.FONT_FAMILY_DEFAULT_BOLD
});
contentStackLayout.Children.Add(new UILabel(14) {
Text = offer.LongRewardsMessage,
TextColor = ColorHelper.FromHex(CoreTheme.COLOR_DEAL_PAGE_LONG_REWARD_MESSAGE_RED),
FontFamily = CoreTheme.FONT_FAMILY_DEFAULT_BOLD
});
if (!string.IsNullOrEmpty(offer.PowerMessage)) {
var htmlText = string.Format("<html><body style='color:#9b9b9b'>{0}</body></html>", offer.PowerMessage.Replace(#"\", string.Empty));
var browser = new WebView() {
HeightRequest = (DeviceDisplaySettings.defaultheight > 600) ? 240 : 150,
Source = new HtmlWebViewSource() { Html = htmlText },
};
browser.Navigating += OnNavigating;
contentStackLayout.Children.Add(browser);
}
var mainRelLayout = new RelativeLayout();
mainRelLayout.Children.Add(savedBtn,
xConstraint: Constraint.Constant(0),
yConstraint: Constraint.Constant(0),
widthConstraint: Constraint.RelativeToParent((parent) =>
{
return parent.Width;
}),
heightConstraint: Constraint.RelativeToParent((parent) =>
{
return 40;
})
);
mainRelLayout.Children.Add(topStackLayout,
Constraint.RelativeToParent((parent) => { return (parent.Width - productImage.Width) / 2; }),
Constraint.RelativeToParent((parent) => { return parent.Y; })
);
mainRelLayout.Children.Add(timeRemainingLabel,
null,
Constraint.RelativeToView(topStackLayout, (parent, sibling) => { return sibling.Height; })
);
mainRelLayout.Children.Add(contentStackLayout,
null,
Constraint.RelativeToView(topStackLayout, (parent, sibling) => { return sibling.Height; })
);
var mainScrollView = new ScrollView()
{
VerticalOptions = LayoutOptions.FillAndExpand,
Orientation = ScrollOrientation.Vertical,
WidthRequest = DeviceDisplaySettings.defaultwidth,
HeightRequest = DeviceDisplaySettings.defaultheight,
Content = mainRelLayout
};
var mainStackLayout = new StackLayout()
{
Spacing = 0,
Padding = new Thickness(0, 0, 0, 0),
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand,
Orientation = StackOrientation.Vertical,
Children = { mainScrollView, redeemBtn }
};
return mainStackLayout;
}
After looking at the wireframe you provided (http://imgur.com/wWBUNud), this is what I would use
(note that I am using XAML here to make the visual structure more obvious)
<?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="FormsSandbox.XamlPage">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ScrollView Orientation="Vertical">
<!---Using StackLayout here to make sure scrolling works as
expected - but put your RelativeLayout content here instead -->
<StackLayout Spacing="0">
<BoxView BackgroundColor="Red" HeightRequest="50"/>
<BoxView BackgroundColor="Yellow" HeightRequest="100"/>
<BoxView BackgroundColor="Red" HeightRequest="50"/>
<BoxView BackgroundColor="Yellow" HeightRequest="100"/>
<BoxView BackgroundColor="Red" HeightRequest="50"/>
<BoxView BackgroundColor="Yellow" HeightRequest="100"/>
<BoxView BackgroundColor="Red" HeightRequest="50"/>
<BoxView BackgroundColor="Yellow" HeightRequest="100"/>
<BoxView BackgroundColor="Red" HeightRequest="50"/>
<BoxView BackgroundColor="Yellow" HeightRequest="100"/>
<BoxView BackgroundColor="Red" HeightRequest="50"/>
<BoxView BackgroundColor="Yellow" HeightRequest="100"/>
<BoxView BackgroundColor="Red" HeightRequest="50"/>
</StackLayout>
</ScrollView>
<Button Grid.Row="1" Text="REDEEM"/>
</Grid>
</ContentPage>
For the aclaration I understand you want something like this:
->ScrollView
->RelativeLayout
->StackLayout
->StackLayout
->Button
But want to fix the button on the bottom even when the page is scrolled.
With that structure is just impossible to do it but it's very easy to fix it with an structure like this:
->StackLayout, VerticalOptions=FillAndExpand
->ScrollView, VerticalOptions=FillAndExpand
->RelativeLayout
->StackLayout
->StackLayout
->Button, VerticalOptions=EndAndExpand
With that structure you will have a root StackLayout where you nest an ScrollView which will fill all the screen except for the space taken by the Button which will stick to the bottom of the screen.
Hope it makes sense.
Cheers.