Is there a way that I can add the ColumnDefinitions into the <grid> - xamarin

My code looks like this:
<Grid VerticalOptions="CenterAndExpand" Padding="20, 0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<local:LabelBodyRendererClass HorizontalOptions="StartAndExpand" Text="Show Subcategory" YAlign="Center" XAlign="Center" />
<Switch x:Name="swtSwitch" Grid.Column="1" Toggled="SwtSwitch" VerticalOptions="Center" HorizontalOptions="End" />
</Grid>
Is there a way that I can add the ColumnDefinitions into the element? My IDE is showing it's an option but I don't know how to specify them.

I don't think you can define it as an attribute. And if you could, it would wreck your readability. Because ColumnDefinition is a complex type, you would have to type the string representation of it, as an array, inside an attribute.
If you want to clean your code, create your own, custom grid which has the columns predefined, but then you would have to expose views as properties, to fill your column. So, you would only save a few lines of the column definitions.

Related

Why an Entry control do not receive the input from user in Xamarin Forms?

enter image description hereI want to implement the xamarin essentials map, but with a floating search for the pins that will appear on this map. I'm using a grid to divide the grid's rows and thus use the first row for the map and the second to show a cardview related to the selected pin. I put the search control in row 0 so that it seems to float on the map.
I couldn't get the focus of the search control to work. I don't know if I'm implementing the InputTransparent property correctly.
Any ideas?
<Grid InputTransparent="False">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="140"/>
</Grid.RowDefinitions>
<maps:Map
x:Name="map"
Grid.Column="0"
Grid.Row="0"
Grid.RowSpan="2"
MapType="Street"
HasZoomEnabled="True"
IsShowingUser="True"
InputTransparent="False"
MoveToLastRegionOnLayoutChange="false"
>
</maps:Map>
<StackLayout Grid.Row="0" Grid.Column="0" InputTransparent="True">
<Frame
Margin="20,40,20,0"
Padding="0"
BorderColor="{StaticResource BlackColor}"
CornerRadius="8"
HeightRequest="35">
<Grid VerticalOptions="CenterAndExpand">
<Grid.RowDefinitions>
<RowDefinition Height="35" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="35" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="35" />
</Grid.ColumnDefinitions>
<Image
Grid.Row="0"
Grid.Column="0"
HeightRequest="20"
HorizontalOptions="Center"
Source="ic_search_bar"
VerticalOptions="Center"
WidthRequest="20" />
<controls:CustomEntry
x:Name="entrySearch"
Grid.Row="0"
Grid.Column="1"
FontSize="14"
HeightRequest="35"
HorizontalOptions="FillAndExpand"
HorizontalTextAlignment="Start"
Keyboard="Text"
Placeholder="¿Qué se te antoja hoy?"
PlaceholderColor="#979797"
ReturnCommand="{Binding SearchCommand}"
InputTransparent="False"
ReturnType="Search"
Text="{Binding SearchText}"
TextChanged="entrySearch_TextChanged"
VerticalOptions="FillAndExpand"
VerticalTextAlignment="Center" />
<Image
Grid.Row="0"
Grid.Column="2"
HeightRequest="15"
HorizontalOptions="Center"
Source="ic_clear_search.png"
VerticalOptions="Center"
WidthRequest="15">
<Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding ClearSearchCommand}" NumberOfTapsRequired="1" />
</Image.GestureRecognizers>
</Image>
</Grid>
</Frame>
</StackLayout>
</Grid>
I try to use the property in many parts of the code
From the docs on InputTransparent
true if neither the element nor its children should receive input and
should, instead, pass inputs to the elements that are visually behind
the current visual element
Your stackLayout is transparent so it’s children, including the Entry, are also transparent
You might be thinking InputTransparent does the opposite of what it actually does. True makes an area effectively invisible to touch; touch goes through it.
If you want an element to be touchable, it has to be "False". BUT all its ancestors must also NOT BLOCK touch.
If you really mean "True", but you have children you want to click on, do this:
<SomeLayoutNameHere InputTransparent="True" CascadeInputTransparent="False" ...>
That allows children to specify whether they can receive touch (InputTransparent=False), or are invisible to touch (=True).
"False" is the default.

How can I make two labels inside two grids appear far left and far right?

I have this XAML:
<Grid BackgroundColor="Red">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" HorizontalOptions="Start">
<Label Text="X" />
</Grid>
<Grid Grid.Column="1" HorizontalOptions="EndAndExpand">
<Label Text="Y" HorizontalOptions="End" />
</Grid>
</Grid>
I wanted to see something like this with a red background from one side to another:
X Y
However what happens is this with a red background from one side to another:
X Y
Can someone give me advice on how I can achieve the effect I want and what might be going wrong? Note that the Label Text that's currently "Y" could actually be much longer and more than half of the width of the screen. Here I just used one character to simplify the question.
Set your main Grid to HorizontalOptions="FillAndExpand" and your columns to take up the full width with *.
Now, you don't need the extra wrapping Grids. You could use them, but it will complicate things. Then set the Labels to HorizontalOptions="Start" and End respectively.
<Grid BackgroundColor="Red" VerticalOptions="Center" HorizontalOptions="FillAndExpand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Text="X" HorizontalOptions="Start"/>
<Label Grid.Column="1" Text="Y" HorizontalOptions="End" />
</Grid>
Resulting in:

Do I need to specify Grid.ColumnDefinitions for a simple two column grid in Xamarin?

I have this code:
<ViewCell x:Name="ss">
<Grid VerticalOptions="CenterAndExpand" Padding="20, 0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<local:LabelBodyRendererClass Grid.Column="0" HorizontalOptions="StartAndExpand" Text="Show Subcategory" />
<Switch x:Name="ssSwitch" Grid.Column="1" Toggled="SsSwitch" VerticalOptions="Center" HorizontalOptions="End" />
</Grid>
</ViewCell>
I found that it still works fine when I remove the column definitions:
<ViewCell x:Name="ss">
<Grid VerticalOptions="CenterAndExpand" Padding="20, 0">
<local:LabelBodyRendererClass Grid.Column="0" HorizontalOptions="StartAndExpand" Text="Show Subcategory" />
<Switch x:Name="ssSwitch" Grid.Column="1" Toggled="SsSwitch" VerticalOptions="Center" HorizontalOptions="End" />
</Grid>
</ViewCell>
So for simple cases like this are they needed. So far I have only been able to see in the iOS simulator. I'm not sure about when it is deployed.
As far as I know, if you want more than one column or row you will need to define them. I can't find anything in the documentation that says otherwise. Even if Xamarin.Forms will generate columns (or rows) for you automatically, it will always have the default width or height setting which is Auto. If you want to have any control over how they layout, you will have to add the definitions and specify widths and heights yourself.
You can easily test it for yourself, like you said you have done. If you want to be sure, create some scenarios where you try to expand the columns or rows without defining them.
You need to specify the ColumnDefinition only when you need specific value for each column. Else each column will share the row's width equally.

Is there a way to code a label and a switch in a ViewCell without using StackLayout?

The application that I am working on has labels and on the right side a switch. Here's a sample of the XAML that is used to achieve this:
<ViewCell x:Name="ss">
<StackLayout VerticalOptions="CenterAndExpand" Padding="20,0,20,0">
<StackLayout Orientation="Horizontal" VerticalOptions="CenterAndExpand">
<StackLayout HorizontalOptions="StartAndExpand" VerticalOptions="Center">
<local:LabelBodyRendererClass Text="Show Subcategory" YAlign="Center" XAlign="Center" />
</StackLayout>
<StackLayout HorizontalOptions="EndAndExpand" Orientation="Horizontal">
<Switch x:Name="ssSwitch" Toggled="SsSwitch" VerticalOptions="Center" />
</StackLayout>
</StackLayout>
</StackLayout>
</ViewCell>
What I would like to find out is if there is a more optimal way to achieve this. The settings page has many switch settings and it seems like there are a large number of elements.
Does anyone have simpler way to achieve the same functionality or should I just stick with the many stacklayout elements?
You can use the built-in SwitchCell but if you want/need to do a custom cell for your layout you can use a Grid instead of the StackLayout. It's more efficient and it's easier to define layouts.
<ViewCell x:Name="ss">
<Grid VerticalOptions="CenterAndExpand" Padding="20, 0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<local:LabelBodyRendererClass HorizontalOptions="StartAndExpand" Text="Show Subcategory" YAlign="Center" XAlign="Center" />
<Switch x:Name="ssSwitch" Grid.Column="1" Toggled="SsSwitch" VerticalOptions="Center" HorizontalOptions="End" />
</Grid>
</ViewCell>
Using your example: you will have a 2-columns 1-row Grid. First column will be your custom control LabelBodyRendererClass and second column will be your switch.
Note that you can apply the Horizontal and Vertical option right in the UI Control.
More about Grid
Udpate
Sure, you can use the SwitchCell from XAML just as you use any other cell.
<SwitchCell x:Name="SS" Text="{Binding Setting1Text}" On="{Binding Setting1}" />
<SwitchCell Text="{Binding Setting2Text}" On="{Binding Setting2}" />
<SwitchCell Text="{Binding Setting3Text}" On="{Binding Setting3}" />
<SwitchCell Text="{Binding Setting4Text}" On="{Binding Setting4}" />
These samples are using binding but as your CustomCell you can use the name to get and set the value from code behind, although I suggest you to use binding.
Hope this helps.-
I guess is that what you are looking for:
Take a look here.

Data bind the index of an item in a listbox?

I have a set of local high scores (ObservableCollection) and they're data bound to a ListBox so I can display them. Here's what I currently have, the "{Binding Index}" of the first TextBlock is where I'm trying to grab the index of the current item but I'm not entirely sure if it's possible through data binding:
<ListBox Grid.Row="1" x:Name="localScoresListBox" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="90" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Index}" Grid.Column="0" />
<TextBlock Text="{Binding PlayerName}" Grid.Column="1" />
<TextBlock Text="{Binding Score}" Grid.Column="2" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
So my question. Using data binding, can you grab the index of the current item?
If it is possible I believe it would be 0-based and since I want the first rank to be 1 instead of 0, could you do something like {Binding Index+1}?
EDIT: There's a similar question here for WPF and there didn't seem to be a way to do it then either: WPF ListBox bind to index of the item
Not that I know of - especially since the item that you are binding will be of whatever type your object is, and it probably doesn't have an Index property.
I'd suggest adding the index property to your data objects (it can be added / manipulated when you populate the collection).

Resources