Let background catch Tapped events? - xaml

I have a grid with a semi transparent background, and I'd like the user to be able to tap the background to close the popup.
Now I have this XAML:
<Grid
Tapped="Close_Tapped">
<Grid.Background>
<SolidColorBrush Color="Black" Opacity=".75"/>
</Grid.Background>
<!-- Inner border -->
<Border
Background="White"
CornerRadius="5">
<!-- Other items -->
</Border>
</Grid>
And the Tapped event should only be applied to the Grid background, but obviously this applies it to the entire grid.
Any ideas to have this Tapped event only work on the background?

You can either check if e.OriginalSource in the Close_Tapped event handler is aGrid or add another element to the Grid, below other elements, which will become your background and then move Tapped handler there
<Grid>
<Border Tapped="Close_Tapped">
<Border.Background>
<SolidColorBrush Color="Black" Opacity=".75"/>
</Border.Background>
</Border>
<!-- Inner border -->
<Border
Background="White"
CornerRadius="5">
<!-- Other items -->
</Border>
</Grid>

Related

Handling both tap and scroll in CollectionView

I'm trying to handle a tap gesture so that when I tap on the CollectionView, it will display a toast. However when I add TapGestureRecognizer, it blocks me from scrolling the collection. I want that it can both scroll and tap to open something. Here's my code so far:
View:
<CollectionView
x:Name="eventsBox"
ItemsSource="{Binding EventList}"
SelectionMode="None"
Header="Events"
ItemsUpdatingScrollMode="KeepLastItemInView">
<CollectionView.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding EventBoxTapCommand}"/>
<SwipeGestureRecognizer
Direction="Up"
Swiped="EventBoxSwiped"/>
<SwipeGestureRecognizer
Direction="Down"
Swiped="EventBoxSwiped"/>
</CollectionView.GestureRecognizers>
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="model:Event">
<HorizontalStackLayout>
<Label Text="{Binding EventDescription}"/>
<Label Text="{Binding EventTime, StringFormat=' at {0}'}"/>
</HorizontalStackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Code behind for Swipe gesture recognizer
private void EventBoxSwiped(object sender, SwipedEventArgs e)
{
switch (e.Direction)
{
case SwipeDirection.Up:
Console.WriteLine("Swiped Up");
//Custon scroll here?
break;
case SwipeDirection.Down:
Console.WriteLine("Swiped Down");
//Custom scroll here?
break;
}
}
I'm thinking of programmatically scroll by recognizing swipe gesture but I haven't found a way to do it. Moreover, the recognition of both tap and swipe is sometime really not responsive.
This is a known issue tracked in Gesture Recognizer Inhibits CollectionView Scrolling.You can follow up there or create a new one on Github.
To fix the issue, you can try to add a ScrollView outside of the CollectionView like below. Also, it is recommended to add Left& Right direction of the swipe gesture in a CollectionView.
<ScrollView>
<CollectionView>
<CollectionView.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding EventBoxTapCommand}"/>
<SwipeGestureRecognizer
Direction="Left"
Swiped="EventBoxSwiped"/>
<SwipeGestureRecognizer
Direction="Right"
Swiped="EventBoxSwiped"/>
</CollectionView.GestureRecognizers>
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="model:Event">
<VerticalStackLayout>
<Label Text="{Binding EventDescription}"/>
<Label Text="{Binding EventTime, StringFormat=' at {0}'}"/>
</VerticalStackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</ScrollView>
After Jason's comment, I came up with a work-around to achieve the effect I want.
I added SelectionMode=Single to the CollectionView and changed the background color of selected item matching the theme color of the app with VisualStateManager. Therefore it appears that no item is selected but still get the tap and scroll event.
<CollectionView
x:Name="eventsBox"
ItemsSource="{Binding EventList}"
SelectionMode="Single"
SelectionChangedCommand="{Binding SelectItemCommand}"
Header="Events"
ItemsUpdatingScrollMode="KeepLastItemInView">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="model:Event">
<HorizontalStackLayout>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState Name="Normal" />
<VisualState Name="Selected">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="{AppThemeBinding Dark=Black, Light=White}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Label Text="{Binding EventDescription}"/>
<Label Text="{Binding EventTime, StringFormat=' at {0}'}"/>
</HorizontalStackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Thanks everyone for the help and information xD

How to make a Stack Panel Visible based on the Tapped Event of a ListView in Windows Phone 8.1?

In my application, I am having a ListView. ListView lists a set of images.
So when the application is running, and when that page is loaded, a list of images are shown.
<ListView ItemsSource="{Binding imageLists}" Background="Red" Tapped="ListView_Tapped">
<ListView.ItemTemplate>
<DataTemplate>
<Grid Background="Green">
<Image Source="{Binding imagePath}" CacheMode="BitmapCache" Stretch="UniformToFill"/>
<StackPanel Name="imageTitle" Visibility="Collapsed" Background="Blue"
HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Foreground="White" Text="Dumy Image Title" FontSize="10"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
As you can see from the code, I have one image & stackpanel inside the listview. And the stackpanel's visibility has been set to collapsed for convenience.
The StackPanel imageTitle resides inside the ListView. Stackpanel contains a TextBlock housing the images name. For now it's dumy text.
On Tapping any image in the list, I am trying to make the stackPanel visible.
The Code Behind:
private void ListView_Tapped(object sender, TappedRoutedEventArgs e)
{
imageTitle.Visibility = Windows.UI.Xaml.Visibility.Visible;
}
Since the stackpanel is inside the listview & I am trying to make it visible on the tap event of the listview, I am not able to acheive the needed result. I know my code is wrong.
If I specify the stackpanel outside the listview, I can make it visible using the code I gave inside the ListView_Tapped function. But even in that case, I need to show the stackpanel (name of the image I clicked) inside the listview item (image I clicked).
Any help??
Can this be achieved using only XAML?
Here's a pure xaml way.
Rather than changing the Visibility of the imageTitle (not a great UX), let's change its Opacity to make its appearing more interesting.
First we need to create a storyboard inside this data template. This storyboard will fade in the imageTitle in 400ms.
And then we drag a ControlStoryboard behavior from Expression Blend's Asset panel onto the top level Grid. Basically we want the storyboard to fire off when this Grid is tapped.
Please see below code for reference.
<DataTemplate x:Key="GroupTemplate">
<Grid Background="Green">
<Grid.Resources>
<Storyboard x:Name="ShowImageTitleStoryboard">
<DoubleAnimation Duration="0:0:0.4" To="1" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="imageTitle"/>
</Storyboard>
</Grid.Resources>
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="Tapped">
<Media:ControlStoryboardAction Storyboard="{StaticResource ShowImageTitleStoryboard}"/>
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
<Image Source="{Binding Image}" CacheMode="BitmapCache" Stretch="UniformToFill"/>
<StackPanel x:Name="imageTitle" Background="Blue"
HorizontalAlignment="Center" VerticalAlignment="Center" Opacity="0">
<TextBlock Foreground="White" Text="Dumy Image Title" FontSize="10"/>
</StackPanel>
</Grid>
</DataTemplate>
Apart from JustinXL's answer it can also be done by using ChangePropertyAction. Also pure XAML:
<DataTemplate>
<Grid Background="Green">
<Image Source="{Binding imagePath}" CacheMode="BitmapCache" Stretch="UniformToFill">
<i:Interaction.Behaviors>
<ic:EventTriggerBehavior EventName="Tapped">
<ic:ChangePropertyAction TargetObject="{Binding ElementName=imageTitle}" PropertyName="Visibility" Value="Visible"/>
</ic:EventTriggerBehavior>
</i:Interaction.Behaviors>
</Image>
<StackPanel Name="imageTitle" Visibility="Collapsed" Background="Blue"
HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Foreground="White" Text="Dumy Image Title" FontSize="10"/>
</StackPanel>
</Grid>
</DataTemplate>
It's just another way to change a property - JustinXL's answer will provide nice animation with opacity, which will look much better.
I dunno why you specifically want to handle the scenario using XAML. For the Microsoft's recommended MVVM model you should bind a property to your element field and then you can write a converter for the same to return back "Visible" or "Collapse".

How to Center a Popup Control on a Page

I have the following Popup that I am using which is by default in the upper left hand corner of the screen. I would like to be able to center this within my view so that I can stretch it to the width and height of the screen as well and change the opacity. I would like the user to be able to see what is behind the popup when it is displayed on the screen, but have the popup cover everything as well. What I have so far is as follows
<Grid x:Name="filterGrid">
<Popup x:Name="trialPopup" HorizontalAlignment="Center" VerticalAlignment="Center" Opacity="0.5">
<Border Margin="3" BorderBrush="{StaticResource PhoneForegroundBrush}">
<StackPanel Background="#FF1BA1E2">
<TextBlock x:Name="modeTextBlock" HorizontalAlignment="Center"/>
<TextBlock Text="Do you wish to purchase the application?" TextWrapping="Wrap" HorizontalAlignment="Center"/>
<Grid Margin="0,10" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width=".5*"/>
<ColumnDefinition Width=".5*"/>
</Grid.ColumnDefinitions>
<Button x:Name="purchaseButton" Grid.Column="0" Content="purchase" Click="popupButton_Click"/>
<Button x:Name="cancelButton" Grid.Column="1" Content="cancel" Click="popupButton_Click"/>
</Grid>
</StackPanel>
</Border>
</Popup>
</Grid>
Whenever I try to set Width="Center" and Height="Center" within the Popup element like the following
<Popup x:Name="trialPopup" HorizontalAlignment="Center" VerticalAlignment="Center">
The top left corner is what is centered, and so the popup is not centered in the middle of the control itself. Is there a way to calculate the proper dimensions based on the popup width and height as well as the page width and height and apply this accordingly? Or is there a way to do this correctly within XAML? Also, the Opacity value is not being set?
Center of Page:
<Popup PlacementTarget="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Page}}}" Placement="Center" />
Center of Window:
<Popup PlacementTarget="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}" Placement="Center" />
Try using Offset properties of Popup:
trialPopup.VerticalOffset = - ((FrameworkElement)trialPopup.Child).ActualHeight / 2;
trialPopup.HorizontalOffset = -((FrameworkElement)trialPopup.Child).ActualWidth / 2;
The Opacity will work when set for the Popup.Child, but I don't know why it won't work on Popup.

I cant place or set background or border of my user control

I've created a simple user control for my xaml project, but as you can see from my image i cant seem to be able to do certain things.
Ignore the red line, its the size of the control for illustrate its size.
It's placement should be middle of the screen:
<Client:TileMenu HorizontalAlignment="Center" VerticalAlignment="Center" Name="TileOverlayMenu" Background="Azure" BorderBrush="Aquamarine" BorderThickness="3" />
And as you see its background color should be "Azure" with a blueish border of 3.
Why is this?
In the background I have a Canvas:
<Grid x:Name="ContentPanel" Grid.Row="0" Margin="12,0,12,0">
<Canvas Name="GameCanvas">
<Canvas.RenderTransform>
<CompositeTransform x:Name="CanvasRenderTransform" />
</Canvas.RenderTransform>
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener DragStarted="GestureListener_DragStarted" DragDelta="GestureListener_DragDelta" Tap="GestureListener_Tap" PinchStarted="GestureListener_PinchStarted" PinchDelta="GestureListener_PinchDelta"/>
</toolkit:GestureService.GestureListener>
</Canvas>
<Client:TileMenu HorizontalAlignment="Center" VerticalAlignment="Center" Name="TileOverlayMenu" Background="Azure" BorderBrush="Aquamarine" BorderThickness="3" />
</Grid>
As for my third problem, having the events in the canvas causes the Move slider to be interrupted, making me only able to push it a little each time :-/
In case TileMenu is a UserControl you would have to set these properties on the top level container in the UserControl's XAML as this defines the entire visual structure of the control.
You could bind to the appropriate values in the UserControl, however:
<UserControl x:Class="YourNamespace.TileMenu" ...
x:Name="tileMenu">
<Border BorderBrush="{Binding BorderBrush, ElementName=tileMenu}"
BorderThickness="{Binding BorderThickness, ElementName=tileMenu}">
<Grid>
...
</Grid>
</Border>
</UserControl>

XAML Rectangle event Tapped doesn't fire in Windows 8

I have a simple Rectangle in XAML
<Rectangle x:Name="rect" IsTapEnabled="True" Height="100" Width="100" Fill="#FF72BB5C" Stroke="#FFFB0000" Tapped="rect_Tapped"/>
It draws fine but when I try and click on it nothing happens.
I have tried making the stroke bigger and clicking that and nothing.
I have tried lots of the other events associated with the Rectangle and nothing fires.
Would there be a problem calling the Tapped event when I'm using a mouse and not a touch screen?
Just faced the same issue. Solved with IsHitTestVisible property for Rectangle and every view above it. True for rect and False for others. Though True is default, could be omitted.
I just found strange and funny solution for this.
If your layout looks like this:
<Grid>
<Canvas>
<Rectangle x:Name="rect" IsTapEnabled="True" Canvas.Top="100" Canvas.Left="100" Height="100" Width="100" Fill="#FF72BB5C" Stroke="#FFFB0000" Tapped="rect_Tapped"/>
</Canvas>
<TextBlock Name="Test" Text="Hi" />
</Grid>
Then change it to this:
<Grid>
<Canvas>
<Rectangle x:Name="rect" IsTapEnabled="True" Canvas.Top="100" Canvas.Left="100" Height="100" Width="100" Fill="#FF72BB5C" Stroke="#FFFB0000" Tapped="rect_Tapped"/>
</Canvas>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Name="Test" Text="Hi" />
</Grid>
I just added VerticalAlignment="Center" HorizontalAlignment="Center" to TextBlock and now it works. Don't know why, but works. I'm going to go deeper into this issue.