Reputation: 1023
This appears to be an issue when running in Windows (haven't tested any other platform yet):
I have a single row & single column Grid with an ImageButton inside of it.
I then added a Label in the Grid so that it renders on top of the ImageButton. So far so good, the Click event works on the ImageButton.
I add one more Label to the same Grid after that, so it renders on top of the other Label, and on top of the ImageButton, and the Click event stops working. What gives?
The purpose of this UI is for a Scrabble game I'm making. This particular element is the tile which is an ImageButton with the appropriate background color, the first Label for the letter, and the second Label for the value of that letter. Example:
Code:
// BoardCell.cs Class for the Scrabble Letter Tile
public class BoardCell : StackLayout
{
public ImageButton TileImageButton { get; private set; }
public Label TileLetterLabel { get; private set; }
public Label TileValueLabel { get; private set; }
public BoardCell(Enums.BoardCellTypes boardCellType)
{
// Setup the TileImageButton
TileImageButton = new ImageButton();
TileImageButton.WidthRequest = 80;
TileImageButton.HeightRequest = 80;
TileImageButton.BorderColor = Colors.DarkGray;
TileImageButton.BorderWidth = 2;
// Setup the Tile Grid
var tileGrid = new Grid();
tileGrid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Star });
tileGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Star });
// Add the Tile Image Button
tileGrid.Children.Add(TileImageButton);
Grid.SetRow(TileImageButton, 0);
Grid.SetColumn(TileImageButton, 0);
// Setup and add the Tile Letter Label
TileLetterLabel = new Label();
TileLetterLabel.TextColor = Colors.Black;
TileLetterLabel.FontSize = 48;
TileLetterLabel.FontAttributes = FontAttributes.Bold;
TileLetterLabel.HorizontalTextAlignment = TextAlignment.Center;
TileLetterLabel.VerticalTextAlignment = TextAlignment.Center;
TileLetterLabel.IsVisible = false; // Important this is initially false, otherwise it blocks clicks on the TileImageButton behind it
tileGrid.Children.Add(TileLetterLabel);
Grid.SetRow(TileLetterLabel, 0);
Grid.SetColumn(TileLetterLabel, 0);
// Setup and add the Tile Value Label
TileValueLabel = new Label();
TileValueLabel.TextColor = Colors.Black;
TileValueLabel.FontSize = 12;
TileValueLabel.FontAttributes = FontAttributes.Bold;
TileValueLabel.HorizontalTextAlignment = TextAlignment.Center;
TileValueLabel.VerticalTextAlignment = TextAlignment.End;
tileGrid.Children.Add(TileValueLabel);
Grid.SetRow(TileValueLabel, 0);
Grid.SetColumn(TileValueLabel, 0);
// Add the tileGrid to the StackLayout of this control
this.Children.Add(tileGrid);
if (boardCellType == Enums.BoardCellTypes.TileLetter)
{
SetTileValueLabel();
TileLetterLabel.IsVisible = true;
}
else
{
TileLetterLabel.IsVisible = false;
}
}
public void SetTileValueLabel()
{
this.TileValueLabel.Text = this.TileValue.ToString();
}
}
// MainPage.xaml.cs
public partial class MainPage : ContentPage
{
BoardCell SelectedTile { get; set; }
public MainPage()
{
BoardTileTapGestureRecognizer = new TapGestureRecognizer();
BoardTileTapGestureRecognizer.Tapped += BoardTileTapGestureRecognizer_Tapped;
InitializeBoard();
MyTileTapGestureRecognizer = new TapGestureRecognizer();
MyTileTapGestureRecognizer.Tapped += MyTileTapGestureRecognizer_Tapped;
}
private void BoardTileTapGestureRecognizer_Tapped(object sender, EventArgs e)
{
// Does a bunch of stuff, but this event doesn't fire with this bug
}
private void MyTileTapGestureRecognizer_Tapped(object sender, EventArgs e)
{
// This one does fire
SelectedTile = GetBoardCellParent(sender); // Sets the SelectedTile to clicked on BoardCell object
}
}
private void InitializeBoard()
{
for (int row = 0; row <= 14; row++)
{
// Setup new row and column for gameboard (only need to do this 15 times for each for a 15x15 grid)
var tileRowDefinition = new RowDefinition() { Height = 80 };
var tileColumnDefinition = new ColumnDefinition() { Width = 80 };
grid_GameBoard.RowDefinitions.Add(tileRowDefinition);
grid_GameBoard.ColumnDefinitions.Add(tileColumnDefinition);
for (int column = 0; column <= 14; column++)
{
// Create a new board cell and set it's clicked event
BoardCell boardCell = GetNewBoardCell(row, column);
boardCell.TileImageButton.Clicked += OnBoardCellClicked;
boardCell.TileLetterLabel.GestureRecognizers.Add(BoardTileTapGestureRecognizer);
// Add the new board cell to the grid
grid_GameBoard.Children.Add(boardCell);
Grid.SetRow(boardCell, row);
Grid.SetColumn(boardCell, column);
}
}
private void OnBoardCellClicked(object sender, EventArgs e)
{
// Does a few things but never gets hit with this bug
}
// MainPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ScrabbleMaui2.MainPage">
<ScrollView>
<!--<Grid RowSpacing="25" RowDefinitions="Auto,Auto,Auto,Auto,*"
Padding="{OnPlatform iOS='30,60,30,30', Default='30'}">-->
<Grid x:Name="grid_Game" RowDefinitions="50,*,100" ColumnDefinitions="*" MaximumHeightRequest="1500">
<Grid x:Name="grid_TitleBar" Grid.Row="0" ColumnDefinitions="*,*,*">
<Grid x:Name="grid_Score" ColumnDefinitions="*,*">
<Label Grid.Column="0" Text="My Score: " />
<Label x:Name="lbl_MyScore" Grid.Column="1" Text="0" />
</Grid>
<Button x:Name="btn_SubmitPlay" Grid.Column="2" Text="Play Word" WidthRequest="100" Clicked="btn_SubmitPlay_Clicked" />
</Grid>
<Grid x:Name="grid_GameBoard" Grid.Row="1" Margin="10" HorizontalOptions="Center" BackgroundColor="Green" />
<Grid x:Name="grid_MyTiles" Grid.Row="2" RowDefinitions="Auto" ColumnDefinitions="*,*,*,*,*,*,*" MaximumWidthRequest="620"
BackgroundColor="Blue" />
</Grid>
</ScrollView>
</ContentPage>
Per ToolmakerSteve's suggestion, I re-arrange the controls I'm using to build my Tile object. I now place a transparent button last, so it's rendered as the top most element. This is the new code in the BoardCell.cs constructor:
public BoardCell(Enums.BoardCellTypes boardCellType, bool isCenterCell)
{
this.IsLocked = false;
this.BoardCellType = boardCellType;
this.IsCenterCell = isCenterCell;
var tileGrid = new Grid();
tileGrid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Star });
tileGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Star });
TileBackground = new Image();
TileLetterLabel = GetLetterLabel();
TileValueLabel = GetValueLabel();
SetTileBackground();
SetTileValueLabel();
TileButton = new Button();
TileButton.WidthRequest = 80;
TileButton.HeightRequest = 80;
TileButton.IsVisible = false;
tileGrid.Children.Add(TileBackground);
tileGrid.Children.Add(TileLetterLabel);
tileGrid.Children.Add(TileValueLabel);
tileGrid.Children.Add(TileButton);
Grid.SetRow(TileBackground, 0);
Grid.SetRow(TileLetterLabel, 0);
Grid.SetRow(TileValueLabel, 0);
Grid.SetRow(TileButton, 0);
Grid.SetColumn(TileBackground, 0);
Grid.SetColumn(TileLetterLabel, 0);
Grid.SetColumn(TileValueLabel, 0);
Grid.SetColumn(TileButton, 0);
this.Children.Add(tileGrid);
}
I'm now using a separate Image
element as the background, and a regular Button
element to be clicked on. Unfortunately I still exhibit the same behavior, oddly. The button's Click
event doesn't fire as long as the TileValueLabel
is added as a child to the Grid
. If I comment out the lines that add it to the Grid
- tileGrid.Children.Add(TileValueLabel);
then Click
event fires.
Upvotes: 0
Views: 86
Reputation: 21233
Sounds like there is a bug with passing input through multiple elements.
Try wrapping the two labels in a second grid, with InputTransparent on that inner grid:
<Grid ..>
<ImageButton ../>
<Grid InputTransparent="True">
<Label ../>
<Label ../>
</Grid>
</Grid>
Upvotes: 0