How do I create different methods when double-tap vs. single-tap?
How to recreate:
Take the default "New Maui App"
Add the first two code blocks from this documentation: https://learn.microsoft.com/en-us/dotnet/maui/fundamentals/gestures/tap?view=net-maui-7.0
Then add a second function for single-tap
The MainPage.Xaml now looks like this (truncated after image part since the rest is the same):
<?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="MauiApp2.MainPage">
<ScrollView>
<VerticalStackLayout
Spacing="25"
Padding="30,0"
VerticalOptions="Center">
<Image
Source="dotnet_bot.png"
SemanticProperties.Description="Cute dot net bot waving hi to you!"
HeightRequest="200"
HorizontalOptions="Center" >
<!--******* add gesture recognizers to default app ******-->
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="OnTapGestureRecognizerDoubleTapped"
NumberOfTapsRequired="2" />
<TapGestureRecognizer Tapped="OnTapGestureRecognizerSingleTapped"
NumberOfTapsRequired="1" />
</Image.GestureRecognizers>
<!--******** end add gesture recognizers to default app *******-->
</Image>
<Label
Text="Hello, World!"
...
Then in MainPage.xaml.cs, I've added the two methods:
void OnTapGestureRecognizerDoubleTapped(object sender, TappedEventArgs args)
{
CounterBtn.Text = $"Double tapped image";
}
void OnTapGestureRecognizerSingleTapped(object sender, TappedEventArgs args)
{
CounterBtn.Text = $"Single tapped image";
}
Now, when you run and double-click/tap the image, it goes first to the single-tap method, then the double-tap method, then back to the single-tap method.
What is the best way to prevent calls to the single-tap method?
By default, the Image will respond to single taps. So single-tap method would be triggered at first tap. When the NumberOfTapsRequired property is set to greater than one, the event handler will only be executed if the taps occur within a set period of time. If the second (or subsequent) taps don't occur within that period, they're effectively ignored.
So as Jason suggested, it's better to use a single tap gesture and track if a 2nd tap is received within some time span.
based on these comments, I implemented the double-tap vs single-tap like this:
bool doubleTapped;
bool ignoreNextTap;
void OnTapGestureRecognizerDoubleTapped(object sender, TappedEventArgs args)
{
doubleTapped = true;
}
async void OnTapGestureRecognizerSingleTapped(object sender, TappedEventArgs args)
{
var delay = Task.Delay(555);
await delay;
if (ignoreNextTap)
{
ignoreNextTap = false;
return;
}
if (doubleTapped)
{
doubleTapped = false;
ignoreNextTap = true;
CounterBtn.Text = $"Double tapped image";
}
else
{
CounterBtn.Text = $"Single tapped image";
}
}
It works, but it sure seems hacky. Basically, what single tap method sleeps for half-of-a-second, to see if the doubleTapped flag will be raised. If it is, then it calls the code that should be executed for doubleTap ("CounterBtn.Text = $"Double tapped image";"). Otherwise, it calls the singleTap code ("CounterBtn.Text = $"Single tapped image";").
However, in order to prevent the second single click from registering, I put another Boolean for ignoreNextTap. I saw similar posts from other languages (How to customize singleclick to doubleclick? js) and the general approach is the same as this. I guess there is no other way to do this other than the Delay/Sleep approach to see if a second click happens. This will generally cut into the snappy-ness of the UI.
Related
Please i will like to know how to achieve a click effect on a stacklayout. I have my design, i use stacklayout and tap gesture to navigate to other pages. However, when i click it feels static and i need to see a click effect.
Below is my design
I want the effect to show when i click any of these options (falut, outage etc) just like when i click on a button control.
Thanks
There are many solutions which can implement it . For example ,you could set the BackgroundColor of the StackLayout in tap directly .
private async void TapGestureRecognizer_Tapped(object sender, EventArgs e)
{
var stack = sender as StackLayout;
stack.BackgroundColor = Color.Black;
await Task.Delay(100); // delay 0.1s
stack.BackgroundColor = Color.LightBlue; // set it to the default color that you define in xaml
//do something you want
}
Solution 2
You could use the plugin XamEffects from nuget .
Usage
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamEffects.Sample"
xmlns:xe="clr-namespace:XamEffects;assembly=XamEffects"
x:Class="xxx.MainPage">
<StackLayout HorizontalOptions="Center"
VerticalOptions="Center"
HeightRequest="100"
WidthRequest="200"
xe:TouchEffect.Color="Red">
//put content of StackLayout here
</StackLayout >
</ContentPage>
I'm making an automatic CarouselView (slider) to slide between images every x seconds. I know there are plenty of examples but none of them helped me to make mine work. So here is the deal:
This is my xaml page:
<CarouselView x:Name="carou_slideshow" Grid.Row="1" IsVisible="False">
<CarouselView.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}"/>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
Whenever the user clicks on the button to start the slideshow, it shows my carousel with its images without any issue but it doesn't change the current image after x seconds. Here's how I've done it :
private void btn_slideShow_Clicked(object sender, EventArgs e)
{
stk_header.IsVisible = false;
stk_options.IsVisible = false;
grid_images.IsVisible = false;
carou_slideshow.IsVisible = true;
carou_slideshow.ItemsSource = sources;
Device.StartTimer(TimeSpan.FromSeconds(5), (Func<bool>)(() =>
{
carou_slideshow.Position = (carou_slideshow.Position + 1) % sources.Count;
return true;
})
);
}
Any idea why ?
EDIT : I realized that in my project I already had a timer in the same class. After removing it and keeping the one in the button method, my application crashes without any error.
EDIT2 : Someone gave me a solution on this post and deleted it after. I tried it and it doesn't work for me.. As I was sure it would, I tried to increment something else and the timer works perfectly fine, but the image doesn't swipe. Also, it can randomly close the application as well as not having any issue.
I'm trying to use a Navigation View in my UWP application. I wrote events for Loaded, SelectionChanged and ItemInvoked. But it's like none of them gets called whatever I do.
This is my Navigation View in XAML
<NavigationView x:Name="nvSample"
Background="{ThemeResource NavigationViewDefaultPaneBackground}"
IsBackButtonVisible="Collapsed"
Loaded="nvTopLevelNav_Loaded"
SelectionChanged="nvTopLevelNav_SelectionChanged"
ItemInvoked="nvTopLevelNav_ItemInvoked">
<NavigationView.MenuItems>
<NavigationViewItem Icon="Home" Content="Home" Tag="Home" />
<NavigationViewItem Icon="Flag" Content="Memory Palace" Tag="SamplePage2" FontFamily="Segoe UI" />
<NavigationViewItem Icon="Accept" Content="Test Arena" Tag="SamplePage3" />
<NavigationViewItem Icon="OtherUser" Content="Sophie" Tag="SamplePage4" />
</NavigationView.MenuItems>
<Frame x:Name="contentFrame" >
</Frame>
</NavigationView>
I wrote provided methods in MainPage.xaml.cs like this
private void nvTopLevelNav_Loaded(object sender, RoutedEventArgs e)
{
Console.WriteLine("in method");
// set the initial SelectedItem
foreach (NavigationViewItemBase item in nvSample.MenuItems)
{
if (item is NavigationViewItem && item.Tag.ToString() == "home")
{
nvSample.SelectedItem = item;
break;
}
}
contentFrame.Navigate(typeof(nvTop.home));
Console.WriteLine("loaded bruh");
}
private void nvTopLevelNav_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args)
{
contentFrame.Navigate(typeof(nvTop.memory_palace));
Console.WriteLine("selection changed");
}
private void nvTopLevelNav_ItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args)
{
contentFrame.Navigate(typeof(nvTop.memory_palace));
Console.WriteLine("item invoked");
}
Console prints for debug purpose only.
In ItemInvoked and SelectionChanged methods I wrote a sample code just to check whether they work. I'll write it completely after.
I think I provided all details.
My problem is my methods for events doesn't get called. How do I correct thet error
Thanks in advance
This works on mine too. I thought this isn't working because I didn't saw any Console messages. So in UWP Console.writeln() doesn't work?
According to your code snippet, you're developing a general UWP app. So, the answer is Yes. If you want to show some debug info in Output window, you could use System.Diagnostics.Debug.WriteLine("something...");.
There's a special case that you could Create a Universal Windows Platform console app. If you're interested in it, you could see that document.
I have a wpf application with a MVVM. I am trying here to build my own close button. Based on this answer Creating a custom Close Button in WPF I added a button event handler in the View(xaml.cs) code. However, it is not recognizing the Close(); call (doesn't exist in the context - Can't resolve symbol).
Also I tried the other answer and added Command and CommandParameter into my button's xaml. But the function behind is not getting hits. In How to bind Close command to a button using the RelayCommand also my wpf is not recognizing RelayCommand. Then How can I use the RelayCommand in wpf said that I have to write it myself(really?). I remember there was a simple way similar to just set an event handler for the button and call Close();. But, how can I do that or why it is not working for me?
View code:
private void closeButton_Click(object sender, RoutedEventArgs e)
{
// I want to call close the whole app on button click
//Close(); is not recognized
}
private void performMainCloseButtonCommand(object Parameter)
{
// This doesn't get hits on button click
Window objWindow = Parameter as Window;
objWindow.Close();
}
Button XAML:
<Button x:Name="closeButton" RenderTransformOrigin="0.5,0.5" Padding="0" Margin="701,0,0,0" BorderThickness="0" Click="closeButton_Click" Command="{Binding MainCloseButtonCommand}" CommandParameter="{Binding ElementName = mainWindow}" Height="45" Width="45" >
<StackPanel Height="45" Width="45">
<Image x:Name="closeButtonImage" Margin="0" Source="/ProjectName;component/Resources/x.fw.png" Height="33"/>
<TextBlock Text="Close" Width="36" Padding="6,0,0,0" HorizontalAlignment="Center" Height="13" FontSize="10"/>
</StackPanel>
</Button>
Close isn't recognized in your event handler because there is probably no method called Close in your current class. If you want to call main window's close method you can use:
private void closeButton_Click(object sender, RoutedEventArgs e)
{
Application.Current.MainWindow.Close();
}
Above is not a good way to do this and does not align with MVVM pattern. Which relates to your second question. Without seeing remaining part of your code, its hard to say why command binding isn't working. My guess you haven't wired up the commands properly for it to fire. You will need to ensure that you have created your RelayCommand instance and your command properties are correctly set.
I am using RichEditBox with XAML and C#
I have following 3 events in XAML and corresponding handlers in C#(back code)
DoubleTapped="RichEditBox_DoubleTapped" RightTapped="RichEditBox_RightTapped" PointerReleased="RichEditBox_PointerReleased"
But after putting debug points, I found, none of them is getting triggered.
DoubleTapped event gets triggered if I double tap not on the word but on empty space within the RichEditBox. Once this event is handled, double tap starts working even on words.
I need to handle any of the above events on words. But none of them is responding as expected.
How can I achieve it?
okies. Got other 2 events working as:
SelectionChanged="RichEditBox_SelectionChanged" Holding="RichEditBox_Holding"
Above events mentioned in the question might be a bug, not sure though.
this is a user control and I've got this code XAML:
<RichEditBox x:Name="TextElementControl" Background="{Binding Background, ElementName=userControlModified}" ManipulationMode="None" ScrollViewer.HorizontalScrollMode="Disabled"
AcceptsReturn="True" TextWrapping="Wrap"
SizeChanged="TextElementControlSizeChanged"
IsDoubleTapEnabled="False" DoubleTapped="TextElementControl_DoubleTapped" BorderThickness="0" BorderBrush="{x:Null}" Padding="10,10,10,10"/>
in the code behind :
private void TextElementControl_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
{
//log message, breakpoint is hitting this during double click.
}
on some portion of the code we've set
void ControlLoaded(object sender, RoutedEventArgs e)
{
TextElementControl.IsReadOnly = false;
}
it works and I hope it helps you.