Trying to implement MAUI Swipe to change Image - swipe

I'm creating a simple page to change the image by swiping. Swipe left gives the next image and swipe right the previous. Unfortunately the swipe events don't trigger.
<?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="Alm.MainPage">
<SwipeView SwipeEnded="SwipeView_SwipeEnded" Threshold="200">
<SwipeItemView>
<Image >
<Image.Source>
<UriImageSource x:Name="Sorsa" Uri="https://someurl.com/someimage.jpg"></UriImageSource>
</Image.Source>
</Image>
</SwipeItemView>
</SwipeView>
</ContentPage>
And the event is:
private void SwipeView_SwipeChanging(object sender, SwipeChangingEventArgs e) {
if (e.SwipeDirection == SwipeDirection.Left)
Sorsa.Uri = HaeEdellinen();
if (e.SwipeDirection == SwipeDirection.Right)
Sorsa.Uri = HaeSeuraava();
}
but it never fires.

You can directly add the Swipe GestureRecognizer to the image and detect the swipe direction: Left or Right to change the source for the image. Here's the code snippet below for your reference:
Xaml:
<Image x:Name="img" HeightRequest="150" WidthRequest="150" Source="logo.png" >
<Image.GestureRecognizers>
<SwipeGestureRecognizer Direction="Left"
Swiped="SwipeGestureRecognizer_Left"/>
<SwipeGestureRecognizer Direction="Right"
Swiped="SwipeGestureRecognizer_Right"/>
</Image.GestureRecognizers>
</Image>
Code-behind:
private void SwipeGestureRecognizer_Left(object sender, SwipedEventArgs e)
{
img.Source = "logo.png";
}
private void SwipeGestureRecognizer_Right(object sender, SwipedEventArgs e)
{
img.Source = "uk.jpg";
}

Related

Mouse click on WPF (Time)Slider has no effect when slider thumb is moving bound to a timer

I use MediaElement and (Time)Slider to play and control playing of a video.
I used answer 2 to this question as a base.
In addition to the dragging capability I would also like the slider thumb to be moved to a mouse click point.
This works ok when the MediaElement and (Time)Slider are paused, but when the video is playing a mouse click has no effect
Here is my code
XAML:
<MediaElement Source="..."
Name="mediaView"
Height="450" LoadedBehavior="Manual" UnloadedBehavior="Stop" Stretch="UniformToFill"
MediaOpened="OnMediaOpened" MediaEnded="OnMediaEnded" MediaFailed="OnMediaFailed" Grid.Row="0" Grid.Column="0"/>
<Grid Name="mediaBar" VerticalAlignment="Bottom" Margin="5,10,5,0" Background="#B2282828" Grid.Row="0" Grid.Column="0">
<!-- ... -->
<Slider Name="timeSlider" Margin="5,5,5,0"
Thumb.DragStarted="OnDragStarted" Thumb.DragCompleted="OnDragCompleted" ValueChanged="OnTimeSliderValueChanged"
PreviewMouseLeftButtonUp="OnMouseLeftButtonUp" IsMoveToPointEnabled="True"
MinWidth="200" FlowDirection="LeftToRight"
Grid.Column="4" Cursor="ScrollWE" VerticalAlignment="Center"/>
<!-- ... -->
</Grid>
relevant c# part:
private void OnDragStarted(object sender, DragStartedEventArgs args)
{
isDragging = true;
ticks.Stop();
}
private void OnDragCompleted(object sender, DragCompletedEventArgs args)
{
isDragging = false;
int SliderValue = (int)timeSlider.Value;
TimeSpan ts = new TimeSpan(0, 0, 0, 0, SliderValue);
mediaView.Position = ts;
if(currentStatus == Status.PLAYING)
ticks.Start();
}
private void OnMouseLeftButtonUp(object sender, EventArgs ea)
{
if(!isDragging)
{
mediaView.Pause();
ticks.Stop();
int SliderValue = (int)timeSlider.Value; // when video is playing this not the point of the mouse click
// ...
}
}
I can understand that timeSlider.Value delivers the current point in time instead of the mouse click position when the video is playing.
Is there another way to measure the position of the mouse click and update the slider value with that ?
Or a better solution for the Mouse-click-while-slider-is-running-situation ?
Try this:
private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs ea)
{
mediaView.Position = TimeSpan.FromSeconds((int)(mediaView.NaturalDuration.TimeSpan.TotalSeconds * (double)(ea.GetPosition(timeSlider).X / this.Width)));
}

Hide WP7 progress bar when the image is loaded

I'm using a progress bar for loading an image in an application for Windows Phone 7.
bitmapImage.DownloadProgress += new EventHandler<DownloadProgressEventArgs (bitmapImage_DownloadProgress);
void bitmapImage_DownloadProgress(object sender, DownloadProgressEventArgs e)
{
progressBar.Value = e.Progress;
}
XAML file:
<ProgressBar x:Name="progressBar" IsIndeterminate="True" Width="300" Height="30" Style="{StaticResource PerformanceProgressBar}" />
I'd like to know the best way to make the progress bar disappear once the image is loaded.
Use the events ImageOpened which triggers when image has been loaded successfully and ImageFailed which triggers if image failed to download.
bitmapImage.ImageOpened += new EventHandler<RoutedEventArgs>(bi_ImageOpened);
bitmapImage.ImageFailed += new EventHandler<ExceptionRoutedEventArgs>(bi_ImageFailed);
void bi_ImageFailed(object sender, ExceptionRoutedEventArgs e)
{
MessageBox.Show("Download of image failed");
progressBar.Visibility = Visibility.Collapsed;
}
void bi_ImageOpened(object sender, RoutedEventArgs e)
{
progressBar.Visibility = Visibility.Collapsed;
}
Simply hide it via the Visibility property
progressBar.Visibility = Visibility.Collapsed

Drag/Drop Button in same application throwing an exception

I have a Canvas that contains a button which I want to be able to drag and drop into another canvas. I want to copy the button to the other Canvas. Here is the code I am using:
The XAML:
<Window>
<Grid>
<Canvas
Height="300"
Width="500"
Background="Gray">
<Canvas
Name="cnvToolBox"
Canvas.Left="10"
Canvas.Top="10"
Background="AliceBlue"
Width="100"
Height="200">
<Button
Content="Drag Me!"
PreviewMouseLeftButtonDown="Button_PreviewMouseLeftButtonDown"
PreviewMouseMove="Button_PreviewMouseMove"></Button>
</Canvas>
<Rectangle
Canvas.Left="119"
Canvas.Top="9"
Width="102"
Height="202"
StrokeDashArray="0.5 1.0 0.3"
Stroke="Black"
StrokeThickness="2"/>
<Canvas
Name="cnvButtonDropZone"
Canvas.Left="120"
Canvas.Top="10"
Width="100"
Height="200"
Background="LightGreen"
AllowDrop="True"
DragEnter="Canvas_DragEnter"
Drop="Canvas_Drop">
</Canvas>
</Canvas>
</Grid>
</Window>
Here's the Code Behind:
public partial class MainWindow : Window
{
private Point startPoint;
public MainWindow()
{
InitializeComponent();
}
private void Button_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
startPoint = e.GetPosition(null);
}
private void Button_PreviewMouseMove(object sender, MouseEventArgs e)
{
Point currentPosition = e.GetPosition(null);
Vector diff = startPoint - currentPosition;
if (e.LeftButton == MouseButtonState.Pressed &&
(Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance ||
Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance))
{
Button button = sender as Button;
DataObject dragData = new DataObject("myFormat", button);
DragDrop.DoDragDrop(button, dragData, DragDropEffects.Copy);
}
}
private void Canvas_DragEnter(object sender, DragEventArgs e)
{
if (!e.Data.GetDataPresent("myFormat") || sender == e.Source)
{
e.Effects = DragDropEffects.None;
}
}
private void Canvas_Drop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent("myFormat"))
{
Button button = e.Data.GetData("myFormat") as Button;
Canvas canvas = sender as Canvas;
canvas.Children.Add(button);
}
}
}
When I drop the button I get the following exception when I'm adding the button to the canvas:
Specified element is already the logical child of another element. Disconnect it first.
I'm just trying to learn how to drag and drop controls and not really sure what that error means and how to resolve it. I don't know where I'm going wrong. Any suggestions would be welcome.
Thanks!
The button is owned by its parent cnvToolBox. You need to remove it from cnvToolBox before adding it to the canvas.
cnvToolBox.Children.Remove(button);
var canvas = sender as Canvas;
canvas.Children.Add(button);
This moves the button from your toolbox to the canvas. If you actually want to clone the item you want something like:
if (e.Data.GetDataPresent("myFormat"))
{
var contentControl = (ContentControl)e.Data.GetData("myFormat");
var constructorInfo = contentControl.GetType().GetConstructor(new Type[] {});
if (constructorInfo != null)
{
var newElement = (UIElement)constructorInfo.Invoke(new object[]{});
var newContentControl = newElement as ContentControl;
if(newContentControl != null)
{
newContentControl.Content = contentControl.Content;
}
((Panel)sender).Children.Add(newElement);
}
}
It's because the Button already has a parent associated with it; the previous Canvas.
You can set the parent of the Button to null; which will essentially remove it from the logical relationship.
button.Parent = null;
You will then be able to add that Button to another Canvas as you have done in your code behind.
You can also remove the Button from the Children property directly if you prefer and then add it accordingly within the new Canvas.
Canvas.Children.Remove(button);

Silverlight Why doesn't this work

I am trying to create a slider(without binding).
Currently i did this:
Xaml:
<Slider Height="68" HorizontalAlignment="Left" Margin="52,45,0,0" x:Name="slider1" VerticalAlignment="Top" Width="256" Minimum="1" Maximum="40" Value="10" ValueChanged="slider1_ValueChanged" />
<TextBlock x:Name="textBlock1" Margin="52,120,0,0" Text="Slide it!" ></TextBlock>
And in my cs:
private void slider1_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) {
textBloxk1.FontSize = slider1.Value;
}
But the silverlight page keeps loading and won't show the slider, anyone know what I'm doing wrong??
Probably at first ValueChanged event, slider1 and textblock1 are still null.
try this:
private void slider1_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (textBlock1 != null && slider1 != null)
{
textBlock1.FontSize = slider1.Value;
}
}
look at your Xaml.. you setting value to 10 Value="10"... but at that time textBlock dosn't exist.. be carefull..
when parser parse Xaml it first create Slider then sets all values to slider (and fire all attached events), and only then it creates TextBlock...
so change you code to this, and everithing should be fine..
private void slider1_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (textBlock1 != null && slider1 != null)
{
textBlock1.FontSize = slider1.Value;
}
}

Is faking a WPF mouseover possible?

I have a data template with a textbox and a button with some styles on it. I would like to have the button show the mouse over state when focus is on the textbox beside it. Is this possible?
I figure it would involve something like this. I can get the textbox through use of FindVisualChild and FindName. Then I can set the GotFocus event on the textbox to do something.
_myTextBox.GotFocus += new RoutedEventHandler(TB_GotFocus);
Here in TB_GotFocus I'm stuck. I can get the button I want to show the mouse over state of, but I don't know what event to send to it. MouseEnterEvent isn't allowed.
void TB_GotFocus(object sender, RoutedEventArgs e)
{
ContentPresenter myContentPresenter = FindVisualChild<ContentPresenter>(this.DataTemplateInstance);
DataTemplate template = myContentPresenter.ContentTemplate;
Button _button= template.FindName("TemplateButton", myContentPresenter) as Button;
_button.RaiseEvent(new RoutedEventArgs(Button.MouseEnterEvent));
}
I don't think it's possible to fake the event but you can force the button to render itself as if it had MouseOver.
private void tb_GotFocus(object sender, RoutedEventArgs e)
{
// ButtonChrome is the first child of button
DependencyObject chrome = VisualTreeHelper.GetChild(button, 0);
chrome.SetValue(Microsoft.Windows.Themes.ButtonChrome.RenderMouseOverProperty, true);
}
private void tb_LostFocus(object sender, RoutedEventArgs e)
{
// ButtonChrome is the first child of button
DependencyObject chrome = VisualTreeHelper.GetChild(button, 0);
chrome.ClearValue(Microsoft.Windows.Themes.ButtonChrome.RenderMouseOverProperty);
}
you need to reference PresentationFramework.Aero.dlll for this to work and then it will only work on Vista for the Aero theme.
If you want it to work for other themes you should make a custom controltemplate for each of the theme you want to support.
See http://blogs.msdn.com/llobo/archive/2006/07/12/663653.aspx for tips
As a follow up to jesperll's comment, I think you can get around making a custom template for each theme by dynamically setting the style to the one you want / null.
Here is my window, with the style defined (but not set to anything).
<Window x:Class="WpfApplication.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<Style TargetType="{x:Type Button}" x:Key="MouseOverStyle">
<Setter Property="Background">
<Setter.Value>Green</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid Height="30">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBox x:Name="MyTextBox" Grid.Column="0" Text="Some Text" Margin="2" GotFocus="TextBox_GotFocus" LostFocus="MyTextBox_LostFocus"/>
<Button x:Name="MyButton" Grid.Column="1" Content="Button" Margin="2" MouseEnter="Button_MouseEnter" MouseLeave="Button_MouseLeave" />
</Grid>
Instead of setting the style via triggers in the template, you can use events in your .cs file like so:
...
public partial class Window1 : Window
{
Style mouseOverStyle;
public Window1()
{
InitializeComponent();
mouseOverStyle = (Style)FindResource("MouseOverStyle");
}
private void TextBox_GotFocus(object sender, RoutedEventArgs e) { MyButton.Style = mouseOverStyle; }
private void MyTextBox_LostFocus(object sender, RoutedEventArgs e) { MyButton.Style = null; }
private void Button_MouseEnter(object sender, MouseEventArgs e) { ((Button)sender).Style = mouseOverStyle; }
private void Button_MouseLeave(object sender, MouseEventArgs e) { ((Button)sender).Style = null; }
}
You get a reference to the style in the constructor and then dynamically set it / unset it. This way, you can define what you want your style to look like in Xaml, and you don't have to rely on any new dependencies.

Resources