I am dynamically generating a grid and am filling it with content through C# code. The code is as follows:
<?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="WPapp.Views.Home"
x:Name="HomeHeader">
<ContentPage.ToolbarItems>
<ToolbarItem Text="Refresh"
x:Name="refreshButton"
Clicked="refreshButton_Clicked"/>
</ContentPage.ToolbarItems>
<ContentPage.Content>
<ScrollView>
<StackLayout Margin="10"
HorizontalOptions="Center"
VerticalOptions="FillAndExpand"
x:Name="HomeContainer"
CompressedLayout.IsHeadless="true">
<Label Text="Featured Posts"
FontSize="Title"
FontAttributes="Bold"
Margin="0, 20, 10, 0"/>
<StackLayout x:Name="FeaturedContainer"
CompressedLayout.IsHeadless="true">
</StackLayout>
</StackLayout>
</ScrollView>
</ContentPage.Content>
</ContentPage>
int columnNum = 0;
int rowNum = 0;
foreach (var category in categoryList)
{
Grid postGrid = new Grid();
var column = new ColumnDefinition();
column.Width = new GridLength(5, GridUnitType.Star);
postGrid.ColumnDefinitions.Add(column);
postGrid.ColumnDefinitions.Add(column);
double division = featuredPosts.Count / 2;
double rowCount = Math.Ceiling(division);
for (int i = 0; i < rowCount; i++)
{
var row = new RowDefinition();
row.Height = GridLength.Auto;
postGrid.RowDefinitions.Add(row);
}
foreach (var item in featuredPosts)
{
Frame featuredFrame = new Frame();
featuredFrame.BorderColor = Color.Gray;
featuredFrame.CornerRadius = 5;
featuredFrame.Padding = 20;
Label postTitle = new Label();
postTitle.FontSize = Device.GetNamedSize(NamedSize.Subtitle, typeof(Label));
postTitle.FontAttributes = FontAttributes.Bold;
BoxView titleSeparator = new BoxView();
titleSeparator.Color = Color.Gray;
titleSeparator.HeightRequest = 1;
titleSeparator.HorizontalOptions = LayoutOptions.Fill;
Image postFeaturedImage = new Image();
postFeaturedImage.Aspect = Aspect.AspectFill;
BoxView imageSeparator = new BoxView();
imageSeparator.Color = Color.Gray;
imageSeparator.HeightRequest = 2;
imageSeparator.HorizontalOptions = LayoutOptions.Fill;
Label publishDate = new Label();
publishDate.FontSize = Device.GetNamedSize(NamedSize.Caption, typeof(Label));
StackLayout postDetails = new StackLayout();
postDetails.Children.Add(postTitle);
postDetails.Children.Add(titleSeparator);
postDetails.Children.Add(postFeaturedImage);
postDetails.Children.Add(imageSeparator);
postDetails.Children.Add(publishDate);
featuredFrame.Content = postDetails;
if ((featuredPosts.First() == item) && !(featuredPosts.Count() % 2 == 0))
{
postGrid.Children.Add(featuredFrame, columnNum, rowNum);
Grid.SetColumnSpan(featuredFrame, 2);
columnNum++;
}
else
{
postGrid.Children.Add(featuredFrame, columnNum, rowNum);
Grid.SetColumnSpan(featuredFrame, 1);
}
columnNum++;
if (columnNum == 2)
{
rowNum++;
columnNum = 0;
}
}
FeaturedContainer.Children.Add(postGrid);
columnNum = 0;
rowNum = 0;
}
With this code, this is the result I am getting:
As you can see, the top-left grid height is sized correctly as it is just big enough to fit its children. This is how it should be.
However, the problem is, sometimes the grid cell becomes too big, this is shown in the bottom-left and bottom-right cells. It is too tall! This is only for some of the cells.
What am I doing wrong and how can I fix this so the grid height is just big enough, not too big.
Related
I am trying to create a dynamic chessboard based on user input(The user inputs 10x 8y and it establishes a 10x8 board). I can't seem to keep the grid inside its own area and fill the full area provided. I was wondering how I would fix this issue
xaml code
<StackLayout >
<StackLayout x:Name="User_Input" BackgroundColor="Green">
<Label Text="Enter Length of Grid" TextColor="Black" FontSize="Body"/>
<Entry x:Name="xEntry" Placeholder="0" />
<Label Text="Enter Width of Grid" TextColor="Black" FontSize="Body"/>
<Entry x:Name="yEntry" Placeholder="0" />
<Button x:Name="btnStart" Clicked="btnStart_Clicked" Text="Start"/>
</StackLayout>
<Frame x:Name="Game" BorderColor="Black">
<Grid x:Name="Game_Grid" BackgroundColor="RoyalBlue" Margin="0" HeightRequest="400" WidthRequest="100">
</Grid>
</Frame>
</StackLayout>
C# Code
private void btnStart_Clicked(object sender, EventArgs e)
{
//User_Input.IsVisible = false;
//Game.IsVisible = true;
int max_x = Int32.Parse(xEntry.Text);
int max_y = Int32.Parse(yEntry.Text);
cellGrid main = new cellGrid(max_x,max_y);
for (int y = 0; y < max_y; y++)
{
ColumnDefinition c = new ColumnDefinition();
c.Width = new GridLength(1, GridUnitType.Auto);
Game_Grid.ColumnDefinitions.Add(c);
for(int x = 0; x < max_x; x++)
{
RowDefinition r = new RowDefinition();
r.Height = new GridLength(1, GridUnitType.Auto);
Game_Grid.RowDefinitions.Add(r);
Label cell = new Label {
HorizontalOptions = LayoutOptions.Fill
,VerticalOptions = LayoutOptions.Fill,
WidthRequest = Game_Grid.WidthRequest / max_x,
HeightRequest = Game_Grid.HeightRequest / max_y,
};
cell.Background = new SolidColorBrush(Color.Black);
Game_Grid.Children.Add(cell, x,y);
}
}
}
Image of the Output
My code creates the grid just like I want to, but my issue is the formatting of it. For example, the below syntax has the grid (using iPhone emulator) start at almost the half-way point of the screen. From best of I can tell, I am only declaring the width of the date column as I do not want it to be drug onto 2 lines if it is a 2 digit month or 2 digit year.
What would be the best way to alter this code so that the grid will span the entire screen in Up & Down format, not Horizontal.
private void LoadInvoiceGrid()
{
List<InvoiceHistory> IH = new List<InvoiceHistory>();
IH = dal.GetInvoices(company);
Grid usergrid = new Grid();
//Adding in this line makes no diff to the display of the grid
usergrid.VerticalOptions = LayoutOptions.FillAndExpand;
//
usergrid.Padding = new Thickness(10, 120, 0, 0);
usergrid.RowDefinitions.Add(new RowDefinition { Height = 50 });
foreach (var item in IH)
usergrid.RowDefinitions.Add(new RowDefinition { Height = 50 });
usergrid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Star });
usergrid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Star });
usergrid.ColumnDefinitions.Add(new ColumnDefinition { Width = 50 });
Label invoicenumHeader = new Label
{
Text = "Invoice #"
};
Label invoiceamountHeader = new Label
{
Text = "Amount"
};
Label invoiceduedateHeader = new Label
{
Text = "Due Date"
};
Grid.SetColumn(invoicenumHeader, 1);
Grid.SetColumn(invoiceamountHeader, 2);
Grid.SetColumn(invoiceduedateHeader, 3);
usergrid.Children.Add(invoicenumHeader);
usergrid.Children.Add(invoiceamountHeader);
usergrid.Children.Add(invoiceduedateHeader);
int rowIndex = 1;
foreach (var item in IH)
{
string date = item.invoiceduedate.Date.ToShortDateString();
Label invoicenum = new Label
{
Text = item.invoicenum.ToString()
};
Label invoiceamount = new Label
{
Text = "$" + item.invoiceamt.ToString("0.##")
};
Label invoiceduedate = new Label
{
Text = date
};
Grid.SetRow(invoicenum, rowIndex);
Grid.SetRow(invoiceamount, rowIndex);
Grid.SetRow(invoiceduedate, rowIndex);
Grid.SetColumn(invoicenum, 1);
Grid.SetColumn(invoiceamount, 2);
Grid.SetColumn(invoiceduedate, 3);
usergrid.Children.Add(invoicenum);
usergrid.Children.Add(invoiceamount);
usergrid.Children.Add(invoiceduedate);
rowIndex++;
}
InvoiceGrid = usergrid;
}
EDIT
In my XAML I have the Vertical Option set to Fill And Expand and it is not making any difference. See my XAML for 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"
x:Class="Pages.DoIt" >
<ContentPage.Content>
<StackLayout Orientation="Vertical" Padding="30" Spacing="40">
<Label TextColor="#77d065" FontSize = "8" Text="Yes, Test, Text" />
<Label TextColor="Blue" FontSize="8" Text="{Binding CompanyWelcomeMessage}" />
<ContentView VerticalOptions="FillAndExpand" Content="{Binding InvoiceGrid,Mode=TwoWay}" Padding="0,10,0,0"/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
I am trying to create a set of stacked horizontal StackLayouts composed of Frames with differing widths. The end goal is to create a Schedule View (multiple calendars viewed at once) not unlike what is possible in Outlook (see attached image).
Desired Output: http://i.stack.imgur.com/1c0mu.png
In trying to do this I noticed that the Width of Frames added to a Horizontal StackLayout will match the WidthRequest only if all of the Frames have the same exact width. If the widths of the Frames differ then the Width and WidthRequests don't match.
Here is the 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"
x:Class="XamarinSample.SamplePage1">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness" iOS="0, 20, 0, 0" />
</ContentPage.Padding>
<ScrollView x:Name="FrozenBandDataScrollView"
Orientation="Horizontal">
<StackLayout VerticalOptions="Start"
HorizontalOptions="Start"
Orientation="Vertical"
Spacing="0"
BackgroundColor="Silver"
WidthRequest="3600"
x:Name="FrozenBandDataStackLayout">
</StackLayout>
</ScrollView>
</ContentPage>
Here is the Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace XamarinSample
{
public partial class SamplePage1 : ContentPage
{
TapGestureRecognizer tapFrameRecognizer = new TapGestureRecognizer();
public SamplePage1()
{
InitializeComponent();
addDataPoints();
}
public void addDataPoints()
{
tapFrameRecognizer.Tapped += (s, e) =>
{
Frame f = s as Frame;
Label l = f.Content as Label;
l.Text = "R:" + f.WidthRequest;
l.Text += ", W: " + f.Width;
l.Text += "\nR: " + f.HeightRequest;
l.Text += ", H: " + f.Height;
};
FrozenBandDataStackLayout.Children.Add(getStackLayoutWithDimensions(70, 3600));
FrozenBandDataStackLayout.Children.Add(getStackLayoutWithDimensions(70, 3600));
FrozenBandDataStackLayout.Children.Add(getStackLayoutWithDimensions(70, 3600));
}
public static double randomNumber(int start, int end){return (new Random()).Next(start, end);}
public StackLayout getStackLayoutWithDimensions(double height, double width)
{
StackLayout sl = new StackLayout {
VerticalOptions = LayoutOptions.Start,
HorizontalOptions = LayoutOptions.Start,
Orientation = StackOrientation.Horizontal,
WidthRequest = width,
HeightRequest = height,
Spacing = 0
};
//OPTION 1: randomly calculated width (total = 3600) -- does not work :(
int minFrameWidth = 1;
int maxFrameWidth = 500;
double currentWidth = 0;
while ((currentWidth + maxFrameWidth) < width)
{
double frameWidth = randomNumber(minFrameWidth, maxFrameWidth);
currentWidth += frameWidth;
sl.Children.Add(getFrameWithDimensions(height, frameWidth));
}
sl.Children.Add(getFrameWithDimensions(height, width-currentWidth));
//OPTION 2: specific homogeneous width (total = 3600) -- works :)
/*
for (int i = 0; i < 12; i++)
{
sl.Children.Add(getFrameWithDimensions(height, 300));
}
*/
//OPTION 3: specific altering width (total = 3600) -- does not work :(
/*
for (int i = 0; i < 12; i++)
{
if (i % 2 == 0) {
sl.Children.Add(getFrameWithDimensions(height, 200));
}else
{
sl.Children.Add(getFrameWithDimensions(height, 400));
}
}
*/
return sl;
}
public Frame getFrameWithDimensions(double height, double width)
{
Frame frame = new Frame
{
BackgroundColor = Color.Gray,
OutlineColor = Color.Black,
HasShadow = false,
HorizontalOptions = LayoutOptions.Start,
WidthRequest = width,
VerticalOptions = LayoutOptions.Start,
HeightRequest = height,
Content = new Label
{
HorizontalTextAlignment = TextAlignment.Center,
VerticalTextAlignment = TextAlignment.Center,
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.Center,
TextColor = Color.Black,
FontFamily = "Arial",
FontSize = 8,
Text = "test"
}
};
frame.GestureRecognizers.Add(tapFrameRecognizer);
return frame;
}
}
}
Here are the three different outputs: http://forums.xamarin.com/discussion/74391/controlled-frame-width-size-in-a-horizontal-stacklayout
Does anyone know a way to assure that the WidthRequest matches the actual Width?
Also, can anyone think of another possible Xamarin Forms solution? I've tried using a Grid but it was really slow (as it's not meant for this type of use). It would be nice to have something with data binding like a horizontal ListView.
Note: This app would need to work for iOS, Windows UWP, and possibly Android.
Here is my code:
Grid gameboard = new Grid();
gameboard.HorizontalAlignment = HorizontalAlignment.Left;
gameboard.VerticalAlignment = VerticalAlignment.Top;
gameboard.Width = Window.Current.Bounds.Width;
gameboard.Height = Window.Current.Bounds.Width;
Border border = new Border();
border.BorderThickness = new Thickness(1);
border.BorderBrush = new SolidColorBrush(Colors.Blue);
for (int j=0;j<7;j++)
{
gameboard.ColumnDefinitions.Add(new ColumnDefinition());
}
for (int i = 0; i < 7; i++)
{
gameboard.RowDefinitions.Add(new RowDefinition());
}
I am a learner, now i want to show my grid lines, can someone help me?
thanks a lot!
Since you are learning, I will help kick start your efforts with something to get you and others in a similar situation to the next step.
Start with code like the following, and tweak it, learn it, research it, and most of all have fun.
XAML
<Grid Name="LayoutRoot" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Margin="30" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
</Grid>
CODE
public MainPage()
{
this.InitializeComponent();
DataContext = this;
Loaded += MainPage_Loaded;
}
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
Grid gameboard = new Grid();
gameboard.HorizontalAlignment = HorizontalAlignment.Stretch;
gameboard.VerticalAlignment = VerticalAlignment.Stretch;
for (int j = 0; j < 7; j++)
{
var cd = new ColumnDefinition();
cd.Width = new GridLength(1, GridUnitType.Star);
var rd = new RowDefinition();
rd.Height = new GridLength(1, GridUnitType.Star);
gameboard.ColumnDefinitions.Add(cd);
gameboard.RowDefinitions.Add(rd);
}
for (int j = 0; j < 7; j++)
{
for (int i = 0; i < 7; i++)
{
Border border = new Border();
border.BorderThickness = new Thickness(1);
border.BorderBrush = new SolidColorBrush(Colors.Blue);
border.HorizontalAlignment = HorizontalAlignment.Stretch;
border.VerticalAlignment = VerticalAlignment.Stretch;
var tb = new TextBlock();
tb.Text = string.Format($"i={i}; j={j}");
tb.Margin = new Thickness(4);
Grid.SetColumn(border, j);
Grid.SetRow(border, i);
border.Child = tb;
gameboard.Children.Add(border);
}
}
LayoutRoot.Children.Add(gameboard);
}
RESULT
SUMMARY
It's a start. It's not perfect, and to get the inner borders to not be thicker than the edges will take a small amount of effort, but should not be too difficult. Hint: think about how to use border.BorderThickness = new Thickness(l, t, r, b); where l/t/r/b are 1 or 0 depending on i/j. I might even make this an interview question; could be a fun discussion.
You can use Grid.ShowGridLines Property and add grid lines.
gameboard.ShowGridLines = true;
I have a window with that structure:
Then in the code behind of the window in the constructor I add the following code:
int numRow = 2;
int numColumn = 3;
for (int row = 0; row < numRow; row++)
{
var rd = new RowDefinition();
rd.Height = new GridLength(1.0, GridUnitType.Star);
grdMain.RowDefinitions.Add(rd);
}
for (int column = 0; column < numColumn; column++)
{
var cd = new ColumnDefinition();
cd.Width = new GridLength(1.0, GridUnitType.Star);
grdMain.ColumnDefinitions.Add(cd);
}
for (int row = 0; row < numRow; row++)
{
for (int column = 0; column < numColumn; column++)
{
//var borderImage = new Border();
//borderImage.BorderThickness = new Thickness(1);
//borderImage.BorderBrush = new SolidColorBrush(Colors.Red);
var finalImage = new Image();
BitmapImage logo = new BitmapImage();
logo.BeginInit();
logo.UriSource = new Uri("pack://application:,,,/EasyRun;component/Resources/Images/ITA.png");
logo.EndInit();
finalImage.Source = logo;
//borderImage.Child = finalImage;
Grid.SetRow(finalImage, row);
Grid.SetColumn(finalImage, column);
grdMain.Children.Add(finalImage);
}
by doing so I expect the window to resize rows and columns accordin to the size of the parent window. But what happens is that while the horizontal stretch works the vertical doesn't.
So in short what I'd like is the grid to stretch columns/rows according to its parent window size
Try using a dockpanel instead then a stack panel
<DockPanel Name="stpMain">
<Button DockPanel.Dock="Bottom" Content="AAA" Width="100" Click="Button_Click"></Button>
<Border BorderThickness="2" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="0" BorderBrush="Red">
<Grid Name="grdMain"></Grid>
</Border>