How to reliably get actual dimensions of a UWP Popup? - windows

I have a UWP App which contains a Page which has 4 Popups defined on it. Each Popup is data-bound to a separate Boolean in the View Model. By manipulating the VM, I can make any of the 4 popus appear - only 1 at a time - maximum.
I would like to control where these Popups appear, so I've added "Opened" event handlers to each of them. The event handlers do the appropriate math to calculate Vertical & HorizontalOffset for the Popups.
This question, which was never answered is my problem as well. To explain it better, querying the popups ActualWidth/Height gives nonsense values. All of my popups are different sizes but all are landscape (width > height). I consistently get ActualWidth=310 & ActualHeight=779 for all of them.
By using the Popup's Child's dimensions (always a Grid) in the math, 2 of the 4 work consistently; the other 2 sometimes work, but usually not. EDIT: They fail because the Grid has no dimensions.
I'm assuming the Opened event is as late as possible to allow all Layout / Measures to occur. Short of hard-coding Heights & Widths on the Popups (one of which will have variable content), I've run out of stuff to try.
There's a lot of code, but they're virtually identical. This is one of the ones that works intermittently ...
<Popup x:Name="LoserTool"
IsOpen="{x:Bind vm.bLoseTool, Mode=OneWay}"
Opened="Popup_Opened"
>
<Grid x:Name="gLoserTool"
Background="{StaticResource TaipanHunter_Primary_Dark}"
BorderBrush="{StaticResource TaipanHunter_Primary_Light}"
BorderThickness="2"
Padding="20"
RowSpacing="10">
<Grid.RowDefinitions>
<RowDefinition Height="1.5*" />
<RowDefinition Height="5*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.2*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="0.2*" />
</Grid.ColumnDefinitions>
<TextBlock Text="Oh No!"
Grid.Column="1"
Grid.Row="0"
Style="{StaticResource TaipanHunter_Title}"
/>
<TextBlock Text="Your tool broke!"
Grid.Column="1"
Grid.Row="1"
Style="{StaticResource Text_LightText}"
/>
<Button Content="Play Again"
Click="StartNewGame"
Grid.Column="1"
Grid.Row="2"
HorizontalAlignment="Center"
Style="{StaticResource Button_Base}"
/>
</Grid>
</Popup>

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:

Adding labels on both ends of a progress bar in Xamarin Forms

I have a progress bar in Xamarin Forms defined in my XAML.
Actually I want to add labels beneath the progress that shows the minimum and maximum value of the progress bar as shown in the image below:
My XAML code:
<StackLayout Orientation="Vertical" Margin="5">
<Frame Padding="10"
BackgroundColor="White"
HeightRequest="80">
<Frame.Content>
<Label Text="%" HorizontalTextAlignment="End" FontSize="Small"/>
<ProgressBar x:Name="myProgressBar" WidthRequest="100"
HeightRequest="15" VerticalOptions="Center" HorizontalOptions="Center" Progress="0.2"/>
</Frame.Content>
</Frame>
</StackLayout>
Can someone please help me to achieve this in Xamarin Forms ? Also, how can I add a gradient color like in the image ?
For the text, you would probably want to use labels positioned under the progressbar. I'd recommend a grid with two rows.
As for the gradient, unfortunately the xamarin forms progress bar doesn't support this out of the box. You can either create a custom renderer for each platform that draws the gradient, or consider a third party control like Syncfusion's (https://www.syncfusion.com/products/xamarin/progress-bar)
You can make a custom Xamarin Forms control.
The content could be something like that:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5* />
<ColumnDefinition Width="0.5* />
</Grid.ColumnDefinition>
<Image x:Name="gradientImage" Grid.Row="0" Grid.ColumnSpan="2" Margin="10,10,10,0" />
<Frame x:Name="progressFrame" Grid.Row="0" Width="{Binding Progress}" HorizontalOption="End" BackgroundColor="Gray" ... />
<!-- Labels -->
<Label x:Name="startLbl" Grid.Row="1" Grid.Column="0" Text="{Binding startLabel}" HorizontalOption="Start" />
<Label x:Name="endLbl" Grid.Row="1" Grid.Column="1" Text="{Binding endLabel}" HorizontalOption="End" />
</Grid>
For the gradient progress bar, instead of CustomRenderers you can use an image.
this image will be the full width gradient bar
over this image, like a MASK, there is a frame. You have to compute the frame width depending on the progress value. ==> It will 'make appear" the gradient image smotthly when progress will increase.
Hope you understand the concept :)
Then in the code behind (in your ViewModel ?) manage the start/end label values and the computation of the "progress" value... I presume you will have to make a Binding Converter for: "progress" ==> "bar Width"...
Tell me if it's clear
Wanted to comment on above answer from #KFactory but don't have permission yet.
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5* />
<ColumnDefinition Width="0.5* />
</Grid.ColumnDefinition>
Has a few typos. missing end quotes and s on closing tag. Should be
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*" />
<ColumnDefinition Width="0.5*" />
</Grid.ColumnDefinitions>

How to use an Image on multiple rows in a Grid properly in Xamarin Forms

I am trying to create a custom, material-style, card cell in my Xamarin Forms app. I have the appearance pretty much down, but I'm having problems with the image in it. I want it to touch the top and bottom edges, the left hand edge, and be a square sort of shape, while maintaining the aspect ratio. But right now, all I get is this small image that won't play ball:
(I've had to cover the company images with paint, but trust me that they're about that size).
Here's what I actually want (again, please excuse the paint job)
I'm using an image in a grid view, in the 1st column and spanning all 4 rows. I've tried all of the LayoutOptions, which I used to understand but now I'm second guessing myself. I've also tried putting the image in a StackLayout as I thought you can expand children of a Stacklayout, but still no dice. Here is my simplified Xaml right now:
<Frame CornerRadius="10"
Margin="10, 5"
IsClippedToBounds="True"
BackgroundColor="White">
<Grid BackgroundColor="White" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackLayout Grid.Row="0" Grid.Column="0" Grid.RowSpan="4"
HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<Image HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" Aspect="AspectFill" Source="{Binding ImageSource}"/>
</StackLayout>
<Label Grid.Row="0" Grid.Column="1"
Text="{Binding Favourite.FavKindName}"
FontSize="{DynamicResource InfoLargerTextFontSize}"/>
<Image Grid.Row="1" Grid.Column="3" Grid.RowSpan="4" Source="Contact.png"
VerticalOptions="CenterAndExpand" >
<Image.GestureRecognizers>
<TapGestureRecognizer />
</Image.GestureRecognizers>
</Image>
</Grid>
</Frame>
What's more, you can probably tell I'm pretty clueless about the phone icon on the right. I want that to occupy the centre and be of a decent button size for the card cell.
I've spent hours trying to figure this out. What am I doing wrong?
Frame has a default Padding of 20. That's why you have those margins inside the frame.
<Frame Padding="0" // Here , set padding to 0, so you can fill all Frame space
CornerRadius="10"
Margin="10, 5"
IsClippedToBounds="True"
BackgroundColor="White">

Xamarin forms Grid sizing issue

I'm new to Xamarin so excuse me if this is very obvious.
I added a Grid to my ContentPage. I want the grid to occupy the entire ContentPage, which I assume is the full size of the device. In my case I'm testing an iPhone 6S simulator.
The first row should be 7.58% of the total height of the Grid and the last one should fill in the rest. I add the label to see where the bottom of the last row is and it shows all the on the top. It looks like it's ~7% from the top which means it's the bottom of the 1st row.
<Grid x:Name="layoutGrid" HorizontalOptions="Fill" VerticalOptions="Fill">
<Grid.RowDefinitions>
<RowDefinition Height=".0758*"/>
<!-- Logo -->
<!-- Remaining Space -->
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=".154*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width=".154*" />
</Grid.ColumnDefinitions>
<Image Aspect="Fill" Source="{local:ImageResource App1.Resources.background.png}" Grid.ColumnSpan="3" Grid.RowSpan="11"/>
<Image Aspect="AspectFit" x:Name="settingsImage" Grid.Column="2" Grid.Row="0" Source="{local:ImageResource App1.Resources.settings-17-xxl.png}" HorizontalOptions="End"/>
<Label x:Name="lblTest" Grid.Row="1" Text="Bottom" TextColor="White" VerticalOptions="End" HorizontalOptions="Center" FontSize="18"/>
It looks like you are placing two items in the same space, which you can not do in a grid. IOW the first image in the XAML (it seems you want this across the entire grid?) does not have a row and column set, but defaults to row/column 0. Then your column span is 3 and row span is 11(?). You only have two rows, so that makes no sense. Also you then can not place the second image in Row 0 column 2 as that is already occupied by the first image. You may want to set the first image as a page background. Or use an Absolute or Relative layout in which you can overlay items. A grid does not allow overlaid items as far as I know. Also you have your vertical options for the label set to "End" which will place it at the bottom of row 1, not the top. Try the following XAML to see if that is closer to what you want:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:App1"
x:Class="App1.MainPage"
BackgroundImage="{local:ImageResource App1.Resources.background.png}">
<Grid x:Name="layoutGrid" HorizontalOptions="Fill" VerticalOptions="Fill">
<Grid.RowDefinitions>
<RowDefinition Height=".0758*"/>
<!-- Logo -->
<!-- Remaining Space -->
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=".154*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width=".154*" />
</Grid.ColumnDefinitions>
<Image Aspect="AspectFit" x:Name="settingsImage" Grid.Column="2" Grid.Row="0" Source="{local:ImageResource App1.Resources.settings-17-xxl.png}" HorizontalOptions="End"/>
<Label x:Name="lblTest" Grid.Row="1" Text="Bottom" TextColor="White" VerticalOptions="Start" HorizontalOptions="Center" FontSize="18"/>
</Grid>
</ContentPage>

Resources