UWP scale manipulation (pinch) events invoked inconsistently - xaml

I'm trying to detect the scale manipulation (pinch) in my application but for some reason the events are not invoked consistently (sometimes they are, sometimes they are not).
I've created a sample application where this can be easily reproduced:
<Page
x:Class="Manipulate.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid Background="Red" ManipulationMode="Scale" ManipulationDelta="Grid_ManipulationDelta" ManipulationStarted="Grid_ManipulationStarted"/>
</Page>
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
namespace Manipulate
{
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
private void Grid_ManipulationStarted(object sender, ManipulationStartedRoutedEventArgs e)
{
System.Diagnostics.Debug.WriteLine($"Started {e.}");
}
private void Grid_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
System.Diagnostics.Debug.WriteLine($"Delta {e.Delta.Scale}");
}
}
}
In my actual application I'm trying to implement pinch to zoom on our custom camera implementation (inspired by https://github.com/microsoft/Windows-universal-samples/tree/master/Samples/CameraManualControls) however I can't seem to get it work because neither ManipulationStarted nor ManipulationDelta are invoked consistently on every pinch gesture.
I'm seeing this on multiple Surface devices (Surface Book, Surface Go, Surface Pro 4).

Please check this Touch interactions document.
Pinch Manipulation gesture Two or more fingers touch the screen and move closer together. In other words, you need to closer two pressed fingers. I have tested with simulator, and it works well. And here is sample code that you could refer.
_compositeTransform.ScaleX = _compositeTransform.ScaleY = e.Delta.Scale;
Update
Derive from #Cosmin It seems there was an issue in the Windows build I was using 20226.1000. The issue was fixed Please check the blog here.

Related

Mouse events are not triggered in Avalonia user control

I'm trying to add Pan and Zoom to custom user control in Avalonia 0.10.10 using mouse wheel and mouse move events.
Standard avalonia template
dotnet new avalonia.mvvm -o Demo
User Control XAML
<UserControl
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="CrossCanvas.Views.Avalonia.CanvasView">
</UserControl>
User Control
public partial class CanvasView : UserControl // Canvas
{
public CanvasView()
{
AvaloniaXamlLoader.Load(this);
PointerMoved += OnMouseMove;
PointerWheelChanged += OnWheel;
}
protected void OnWheel(object sender, PointerWheelEventArgs e) {}
protected void OnMouseMove(object sender, PointerEventArgs e) {}
}
Code that was used as an example
https://github.com/AvaloniaUI/Avalonia/issues/2492#issuecomment-489898224
The issue
No matter where I add new event handlers, in the constructor or in EndInit handler, these events are not being triggered. Maybe Avalonia 0.10.10 had some breaking changes or I do something wrong?
UserControl is invisible for hit test (pointer input) for obvious reasons to avoid it being blocking input from any other control behind it.
But you can easily make it visible for hit test by making it "visible" - set Background to non-null value. For example, "Transparent".

UWP - Save attributes of a xaml page (Slider/Combobox)

I've got the following problem: In my main xaml page I've got a button which navigates to an other page which is called settings and which also includes settings for the app. I jump to the page with the following method:
this->Frame->Navigate(Windows::UI::Xaml::Interop::TypeName(Settings::typeid));
As you can understand I want the UI-Elements (Comboboxes/Sliders) to save theier attributes for the next time. Not even for the next launch of the app, just for the next jump on the settings page. If I go back from settings to main page and back to settings again, the values of the comboboxes and slider are reseted. I need them to be saved for my program's logic.
In my c++-desktop app I'm using registry entrys in order to save it, but this is not quite possible in uwp and it's not the easiest solution. In Java I would use a global static variable which saves the values and which is bind to UI-elements. How can I implement this in UWP ?
You can achieve that with the Page.NavigationCacheMode Property. With that property you are able to store the state of the page in the cache of the application.
You can either use it in the xaml-tag of the page, or set in the constructor in the code-behind of the page. You can find the possible values of the properties here.
Example-XAML:
<Page
x:Class="Foo.Namespace.SettingsPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Foo.Namespace"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
NavigationCacheMode="Enabled">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
</Grid>
</Page>
Example CS:
public sealed partial class SettingsPage : Page
{
public SettingsPage()
{
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Enabled;
}
}

Play sound clip in Windows Phone 8

I'm trying to do something that I thought would be pretty simple, but its not proving that way. I want to play a sound clip from a URI that I'm obtaining from an API. The URI provides an absolute URI to the audio clip.
I've tried using the MediaElement component and that works, except it hangs the UI while the clip is downloading/playing. This means a poor user experience and probably wouldn't get past store certification either.
I've also tried the SoundEffect class from the XNA framework, but that complains about an absolute URI – it seems this only works with relative links and thus wont suffice.
I'm wondering what other options I have for playing a sound clip in a windows phone 8 app that wont hang the UI
Any suggestions welcomed.
Thanks
Using media files on a network or the Internet is going to add latency to the app. You can't start playing the media until the phone has loaded the file. Use the MediaElement.MediaOpened to determine when the media is ready, then call .Play();
Of course, you need to let the users know that the media is downloading. My example uses the SystemTray ProgressIndicator to show the user a message.
XAML
<Grid x:Name="ContentPanel"
Grid.Row="1"
Margin="12,0,12,0">
<StackPanel>
<Button x:Name='PlayButton'
Click='PlayButton_Click'
Content='Play Media' />
<MediaElement x:Name='media1'
MediaOpened='Media1_MediaOpened'
AutoPlay='False' />
</StackPanel>
</Grid>
CODE
private void Media1_MediaOpened(object sender, RoutedEventArgs e) {
// MediaOpened event occurs when the media stream has been
// validated and opened, and the file headers have been read.
ShowProgressIndicator(false);
media1.Play();
}
private void PlayButton_Click(object sender, RoutedEventArgs e) {
// the SystemTray has a ProgressIndicator
// that you can use to display progress during async operations.
SystemTray.ProgressIndicator = new ProgressIndicator();
SystemTray.ProgressIndicator.Text = "Acquiring media - OverTheTop.mp3 ";
ShowProgressIndicator(true);
// Get the media
media1.Source =
new Uri(#"http://freesologuitar.com/mps/DonAlder_OverTheTop.mp3",
UriKind.Absolute);
}
private static void ShowProgressIndicator(bool isVisible) {
SystemTray.ProgressIndicator.IsIndeterminate = isVisible;
SystemTray.ProgressIndicator.IsVisible = isVisible;
}

How to Keep Button Upright When Device Position Changes

I'd like to be able to allow a button that I have in my application to always remain looking like it is in the upright position, even when the device is rotated clockwise or counterclockwise. The standard app bar kind of does this with adjusting the application bar icons according to whether the device is in portrait or landscape mode, so I'd like to do something similar with a button on my page. How might I do something like this? Any recommendations into the methods? I'd like to either stick with something like what the app bar already does, or always rotate the button so it remains upright as the device rotates.
<Button x:Name="CameraButton" Grid.Row="1" Grid.Column="0" Margin="-48,0,0,-12"
Click="CameraButton_Click">
<Button.Content>
<Image Source="/Assets/Camera_Button1.png"/>
</Button.Content>
</Button>
If you do not care the rotate animation auto played by system, you can easily achieve by providing 3 different icons(Portrait, LandscapeLeft, LandscapeRight).
In Xaml, you first add your ApplicationBarIconButton into the page Resource, and change its IconUri later when OrientationChanged is fired. Hope it helps.
The project code can be downloaded here:
http://hdtp.synology.me/ApplicationBarIconDirection.zip
xaml code:
<phone:PhoneApplicationPage
x:Class="ApplicationBarIconDirection.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape" Orientation="Portrait"
shell:SystemTray.IsVisible="True"
OrientationChanged="PhoneApplicationPage_OrientationChanged">
<phone:PhoneApplicationPage.Resources>
<shell:ApplicationBarIconButton x:Key="icon_arrow" IconUri="/Assets/up.png" Text="FixedUp"/>
</phone:PhoneApplicationPage.Resources>
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
</Grid>
<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>
</phone:PhoneApplicationPage>
xaml.cs code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Shell;
namespace ApplicationBarIconDirection
{
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
this.ApplicationBar.Buttons.Add(this.Resources["icon_arrow"] as ApplicationBarIconButton);
}
private void PhoneApplicationPage_OrientationChanged(object sender, OrientationChangedEventArgs e)
{
if (e.Orientation == PageOrientation.LandscapeLeft)
{
(this.Resources["icon_arrow"] as ApplicationBarIconButton).IconUri = new Uri("/Assets/left.png", UriKind.Relative);
}
else if (e.Orientation == PageOrientation.LandscapeRight)
{
(this.Resources["icon_arrow"] as ApplicationBarIconButton).IconUri = new Uri("/Assets/right.png", UriKind.Relative);
}
else
{
(this.Resources["icon_arrow"] as ApplicationBarIconButton).IconUri = new Uri("/Assets/up.png", UriKind.Relative);
}
}
}
}
Application Bar has a property named SupportedOrientation which makes it change its orientation every time the orientation of the phone changes (see this ). But, If we look at button then we see that there is neither such property named SupportedOrientation nor any other property functioning analogous to that of SupportedOrientation for applicationbar. I would hence recommend you to make your own logic according to the changes in the phones orientation.
sample logic to change orientations-
logic to rotate a button
CompositeTransform ct=new CompositeTransform (){Rotation=90};
button.Rendertransform=ct;
Apply this on orientation changes like this
private void PhoneApplicationPage_OrientationChanged(object sender, OrientationChangedEventArgs e)
{
if (e.Orientation == PageOrientation.LandscapeLeft)
{
//apply rotation with some angle say 90
}
else if (e.Orientation == PageOrientation.LandscapeRight)
{
//apply rotation 180
}
else if(e.Orientation == PageOrientation.PortraitUp)
{
//apply rotation 270
}
else if(e.Orientation == PageOrientation.PortraitDown)
{
//apply rotation 360
}
}
And for smoothness like that in applicationbar buttons you would have to make your hands dirty with the storyboards and animations using expression blend

What is the difference between null and transparent brush in the Background or Fill

For example we have a Border. What the difference beetween these XAMLs?
1) Background="Transparent"
<Page
x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Border
BorderBrush="White"
BorderThickness="2"
Width="400"
Height="400"
Background="Transparent"
PointerPressed="Border_PointerPressed"
PointerReleased="Border_PointerReleased" />
</Grid>
2) Background="{x:Null}"
<Page
x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Border
BorderBrush="White"
BorderThickness="2"
Width="400"
Height="400"
Background="{x:Null}"
PointerPressed="Border_PointerPressed"
PointerReleased="Border_PointerReleased" />
</Grid>
Both of these borders looks identical. But what the difference?
The difference is if we set null background the Border will not support hit-testing, that's why routed events like PonterPressed will not be raised.
Conversely though, if we set Transparent background events will be raised.
To illustrate this let's write code-behind.
using Windows.UI.Xaml.Media;
namespace App1 {
public sealed partial class MainPage : Page {
public MainPage() {
this.InitializeComponent();
}
void Border_PointerPressed(object sender, PointerRoutedEventArgs e) {
Border border = sender as Border;
if (border != null)
border.Background = new SolidColorBrush(Colors.Red);
}
void Border_PointerReleased(object sender, PointerRoutedEventArgs e) {
Border border = sender as Border;
if (border != null)
border.Background = new SolidColorBrush(Colors.Transparent);
}
}
}
1) Let's use the first XAML, compile our app and run it. Try to tap inside the square. The square becomes red because the events are rised and the handlers calls.
2) Now let's use the second XAML, compile the app, run it, tap inside the square. Nothing happens because the events are not rised. The handlers are not calls.
For completeness, I found this link http://msdn.microsoft.com/en-us/library/hh758286.aspx#hit_testing explaining this rather well - see especially the second bullet point:
Hit testing and input events
Determining whether and where in UI an element is visible to mouse,
touch, and stylus input is called hit testing. For touch actions and
also for interaction-specific or manipulation events that are
consequences of a touch action, an element must be hit-test visible in
order to be the event source and fire the event that is associated
with the action. Otherwise, the action passes through the element to
any underlying elements or parent elements in the visual tree that
could interact with that input. There are several factors that affect
hit testing, but you can determine whether a given element can fire
input events by checking its IsHitTestVisible property. This property
returns true only if the element meets these criteria:
The element's Visibility property value is Visible.
The element's Background or Fill property value is not null. A null Brush value results in transparency and hit test invisibility. (To
make an element transparent but also hit testable, use a Transparent
brush instead of null.) Note Background and Fill aren't defined by
UIElement, and are instead defined by different derived classes such
as Control and Shape. But the implications of brushes you use for
foreground and background properties are the same for hit testing and
input events, no matter which subclass implements the properties.
If the element is a control, its IsEnabled property value must be true.
The element must have actual dimensions in layout. An element where either ActualHeight and ActualWidth are 0 won't fire input events.