I can't get why my canvas doesn't get pointer events. Below my code and a part of the XAML layout:
XAML
<Canvas
x:Name="cPad"
Canvas.ZIndex="99"
Grid.Column="0"
PointerPressed="Pad_PointerPressed">
<Rectangle
x:Name="rPicker"
Width="24"
Height="24"
Stroke="Black"
Fill="White"
StrokeThickness="3"/>
</Canvas>
C#
private void Pad_PointerPressed(object sender, PointerRoutedEventArgs e)
{
cPad.CapturePointer(e.Pointer);
var point = e.GetCurrentPoint(cPad).Position;
Canvas.SetLeft(rPicker, point.X);
Canvas.SetTop(rPicker, point.Y);
e.Handled = true;
}
The problem that rPicker moves only if I click on rPicker... But I need to Pad_PointerPressed executes for any point on canvas. How can I make it?
Set Canvas.Background property to Transparent to enable PointerPressed events:
<Canvas
...
Background="Transparent"
>
...
</Canvas>
Related
I have Image on View that I can drag. But when I release the object it is moving for some time. How I can disable this?
My Xaml code:
<Image Grid.Column="0"
x:Name="CollageImg1"
Margin="370,469,1665,800"
Source="{Binding CollageImg1}"
RenderTransformOrigin="0.5,0.5"
ManipulationDelta="CollageImgage1_Manipulation"
Visibility="Visible">
<Image.RenderTransform>
<CompositeTransform />
</Image.RenderTransform>
</Image>
Method that uses for moving:
private void Manipulation(ManipulationDeltaRoutedEventArgs e, Image image)
{
CompositeTransform ct = (CompositeTransform)image.RenderTransform;
ct.TranslateX += e.Delta.Translation.X;// X move
ct.TranslateY += e.Delta.Translation.Y;// Ymove
}
Remove TranslateInertia from the ManipulationMode property of the Image.
E.g. set only TranslateX and TranslateY:
<Image ManipulationMode="TranslateX,TranslateY" ... />
I have an InkCanvas over the front of my application.
I want it to only interact with Stylus/Pen events. All other events should be passed through to the various controls underneath the canvas.
The intention is that I detect gestures on the InkCanvas with a pen, while other manipulation events are handled by the controls below the InkCanvas (such as touch and inertial manipulation).
Currently I've tried disabling manipulation events, capturing them, setting handled = false. So far I can't find the right solution. Any ideas?
You can detect the input mode (PointerDeviceType) in the Pointer events of the InkCanvas, for example:
<ScrollViewer x:Name="scrollViewer" Width="400" Height="400" Background="LightBlue" VerticalAlignment="Center" HorizontalAlignment="Center"
PointerPressed="scrollViewer_PointerPressed">
<StackPanel>
<Rectangle Height="300" Width="300" Fill="Red"/>
<Rectangle Height="300" Width="300" Fill="Black"/>
</StackPanel>
</ScrollViewer>
<InkCanvas x:Name="inkCanvas" Width="400" Height="400" GotFocus="inkCanvas_GotFocus" VerticalAlignment="Center" HorizontalAlignment="Center"
Tapped="inkCanvas_Tapped" PointerPressed="inkCanvas_PointerPressed"/>
code behind:
private void inkCanvas_PointerPressed(object sender, PointerRoutedEventArgs e)
{
// Accept input only from a pen or mouse with the left button pressed.
PointerDeviceType pointerDevType = e.Pointer.PointerDeviceType;
if (pointerDevType == PointerDeviceType.Pen)
{
//TODO:
}
else
{
// Process touch or mouse input
inkCanvas.Visibility = Visibility.Collapsed;
}
}
private void scrollViewer_PointerPressed(object sender, PointerRoutedEventArgs e)
{
PointerDeviceType pointerDevType = e.Pointer.PointerDeviceType;
if (pointerDevType == PointerDeviceType.Pen)
{
inkCanvas.Visibility = Visibility.Visible;
}
else
{
// Process touch or mouse input
inkCanvas.Visibility = Visibility.Collapsed;
}
}
Basically, I'm trying to make the canvas listen for a touch input (tap) and will increment the number of taps on screen. It isn't working when I touch the screen on my device. I debugged my code and nothing seems out of the ordinary except that the touch is not detected. I checked ZIndex and the canvas is in front of the screen to be touchable. How do I make it work?
XAML:
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<TextBlock Name="counter" FontSize="150" HorizontalAlignment="Center" TextWrapping="Wrap" Text="0" VerticalAlignment="Center" Margin="188,10,187,397"/>
<Button Content="Reset" HorizontalAlignment="Stretch" Margin="-18,535,-18,0" VerticalAlignment="Top" Click="Button_Click"/>
<Canvas ZIndex="0" Name="Canvas" HorizontalAlignment="Center" Height="535" VerticalAlignment="Top" Width="446" MouseLeftButtonDown="Canvas_MouseLeftButtonDown" MouseLeftButtonUp="Canvas_MouseLeftButtonUp" MouseLeave="Canvas_MouseLeave"/>
</Grid>
C#:
int taps = 0; // create var to detect number of times, user touches the screen
// Constructor
public MainPage()
{
InitializeComponent();
}
// method to register the touch as the finger is placed on the screen
private void Canvas_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
//Canvas c = sender as Canvas;
counter.Text = "TOUCHED!";
}
//method register the touch as the finger is lifting up from the screen
private void Canvas_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
//Canvas c = sender as Canvas;
taps++;
counter.Text = taps.ToString(); //convert var from int to string
}
//method register the touch as the finger leaves the area of the screen
private void Canvas_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
//Canvas c = sender as Canvas;
MessageBox.Show("You left the screen without lifting your finger. That does not count as a tap!", "Caution!", MessageBoxButton.OK);
}
// method to reset the counter to zero when button is pressed and released
private void Button_Click(object sender, RoutedEventArgs e)
{
taps = 0; // reset the count
counter.Text = taps.ToString(); // convert var from int to string
}
I don't know why you want to do it with Canvas - it won't work as you have nothing in this Canvas, so it can't register your click/tap, Canvas is also hard to adjust to screen. I think it can be done simpler way if you want to do it with MouseUp/Down - subscribe directly to Grid containing your elements instead of filling this Grid with additional Canvas:
In XAML:
<Grid x:Name="ContentPanel" Margin="12,0,12,0" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="7*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<TextBlock Name="counter" FontSize="150" HorizontalAlignment="Center" TextWrapping="Wrap" Text="0" VerticalAlignment="Center" Grid.Row="0"/>
<Button Content="Reset" HorizontalAlignment="Stretch" VerticalAlignment="Center" Click="Button_Click" Grid.Row="1"/>
<TextBlock Name="Touched" FontSize="50" HorizontalAlignment="Center" TextWrapping="Wrap" Text="Touched" VerticalAlignment="Center" Visibility="Collapsed" Grid.Row="2"/>
</Grid>
In code behind:
private int taps = 0;
public MainPage()
{
InitializeComponent();
ContentPanel.MouseLeftButtonDown += ContentPanel_MouseLeftButtonDown;
ContentPanel.MouseLeftButtonUp += ContentPanel_MouseLeftButtonUp;
}
private void ContentPanel_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
taps++;
counter.Text = taps.ToString(); //convert var from int to string
Touched.Visibility = Visibility.Collapsed;
}
private void ContentPanel_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
Touched.Visibility = Visibility.Visible;
}
// method to reset the counter to zero when button is pressed and released
private void Button_Click(object sender, RoutedEventArgs e)
{
taps = 0; // reset the count
counter.Text = taps.ToString(); // convert var from int to string
}
As you can see I've subscribed to Grid events (which covers whole screen) - but to make it work I had to set its Background Brush to Transparent, otherwise it will work only if you touch text.
There are many other ways to make your App work, but I hope this will help.
Is there a reason why you don't use the touch-events?
Instead of using MouseLeftButtonDown and MouseLeftButtonUp you should use TouchDown and TouchUp.
Only when you don't handle the touch events or the manipulation events they will be mapped to mouse events. In my experience with touch a single tap also not always gets mapped to MouseLeftButtonDown. As far as I know you could also with mouse events only recoginse one finger. When you want to count more fingers it's necessary to use the TouchDown/TouchUp events.
The problem lies in the overlapping style of the grid
so either make grid rows or define a stackpanel inside the grid, something like this.
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<stackpanel>
<TextBlock Name="counter" FontSize="150" HorizontalAlignment="Center" TextWrapping="Wrap" Text="0" Margin="0,0,0,0"/>
<Canvas ZIndex="0" Name="Canvas" HorizontalAlignment="Center" Height="535" VerticalAlignment="Top" Width="446" MouseLeftButtonDown="Canvas_MouseLeftButtonDown" MouseLeftButtonUp="Canvas_MouseLeftButtonUp" MouseLeave="Canvas_MouseLeave"/>
<Button Content="Reset" HorizontalAlignment="Stretch" Margin="0,0,0,0" VerticalAlignment="Top" Click="Button_Click"/>
</stackpanel>
</Grid>
Try and check now.
You should set your Background property. If you don't want any background set it to Transparent:
<Canvas ZIndex="99" Background="Transparent" Name="Canvas" HorizontalAlignment="Center" Height="535" VerticalAlignment="Top" Width="446" Tapped="Canvas_CountMyTaps"/>
(If you want the canvas to be on Top be sure to make it have a greater ZIndex than the other elements that it overlaps)
If not set (the default value is null) the element won't capture any taps/click etc, it will be as if they "fall through".
Also, consider using the Tapped event which is a "higher level" event that will respond to clicks, taps with the finger, stylus, etc.
I want to add some images or controls dynamically in my canvas control and for each control I want to get its gesture event. How I Would I get that what will be the best approach.
void AddText()
{
TextBlock name = new TextBlock();
name.Text = "This is text " + Count;
Random rnd1 = new Random();
name.Width = rnd1.Next(0, 400);
name.Height = rnd1.Next(0, 800);
var gl = GestureService.GetGestureListener(name);
gl.Tap += new EventHandler<GestureEventArgs>(GestureListener_Tap);
gl.Hold += new EventHandler<GestureEventArgs>(GestureListener_Hold);
canvas1.Children.Add(name);
}
private void GestureListener_Tap(object sender, GestureEventArgs e)
{
MessageBox.Show("I Am Tapped");
}
private void GestureListener_Hold(object sender, GestureEventArgs e)
{
MessageBox.Show("I Am Holded");
}
But in this way my all controls are placed on same place even I used random function for thier width and height. And other thing when I tap on any textblock that i created with this way. It calls all gesture events.
Unlike StackPanel, Canvas control behaves like absolute positioning in HTML/CSS. Each element will be given its own specific location on the page. With elements absolutely positioned, they don’t adjust. Elements will overlap, without having any positioning-related effect on its neighbors.
<Canvas>
<Rectangle Fill="Red" Width="100" Height="100" Canvas.Top="100" Canvas.Left="100" />
<Rectangle Fill="Orange" Width="100" Height="100" Canvas.Top="100" Canvas.Left="200" />
<Rectangle Fill="Green" Width="100" Height="100" Canvas.Top="200" Canvas.Left="100" />
<Rectangle Fill="Blue" Width="100" Height="100" Canvas.Top="200" Canvas.Left="200" />
</Canvas>
For each element in your Canvas, you will need to specify the Canvas.Top and Canvas.Left properties. Omitting these values will result in your elements being positioned in the top left corner of the Canvas, at position 0,0.
So you need to provide Left and Top properties as shown below,
Canvas.SetLeft(name, 50);
Canvas.SetTop(name, 100);
I am trying to have the location of an image change when I mouseover. I have:
<Image
Name="cat"
Source="CatRun.bmp"
Visibility="Hidden"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Width="100"
Height="100"
UIElement.MouseEnter="cat_MouseEnter"/>
in XAML and:
private void cat_MouseEnter(object sender, MouseEventArgs e)
{
}
in C#.
How can I set the location specifically on the canvas?
Here's an example:
<Canvas x:Name="canvas">
<Rectangle x:Name="rect" Width="20" Height="20" Canvas.Left="10" Canvas.Top="10" Fill="Blue" MouseEnter="RectangleMouseEnter" />
</Canvas>
You need to set the attached properties top, left (or bottom, right)
private void RectangleMouseEnter(object sender, MouseEventArgs e)
{
Canvas.SetTop(rect, 50);
Canvas.SetLeft(rect, 50);
}
In order to set position of the Image on the Canvas from code-behind you can use something like:
private void cat_MouseEnter(object sender, MouseEventArgs e)
{
Canvas.SetLeft(cat, 100); //set x coordinate of cat Image to 100
Canvas.SetTop(cat, 300); //set y coordinate of cat Image to 300
}
Update:
In some cases you may not be able to access cat object by name from that method. In order to make it work, just use the sender object that should be the Image that caused the event, as H.B. described in his comment.