WPF controls do not behave as expected with multi-touch - c#

I am creating an application in WPF that relies on multi-touch and, although I can receive multiple touch points, the WPF controls do not behave as expected when multiple touches occur at the same time.
I created a simple test WPF application using buttons for visualization to ensure it wasn't anything in my project causing the issue.
The XAML:
<Window x:Class="TouchSample3.MainWindow"
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"
xmlns:local="clr-namespace:TouchSample3"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid TouchDown="Grid_TouchDown">
<Button x:Name="button1" Content="Button" HorizontalAlignment="Left" Margin="108,86,0,0" VerticalAlignment="Top" Width="70" Height="70" Click="button1_Click" TouchDown="button1_TouchDown"/>
<Button x:Name="button2" Content="Button" HorizontalAlignment="Left" Margin="322,86,0,0" VerticalAlignment="Top" Width="70" Height="70" Click="button2_Click" TouchDown="button2_TouchDown"/>
</Grid>
</Window>
and here is my MainWindow:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
Console.WriteLine("Button 1 clicked.");
}
private void button2_Click(object sender, RoutedEventArgs e)
{
Console.WriteLine("Button 2 clicked.");
}
// TouchDown events
private void button1_TouchDown(object sender, TouchEventArgs e)
{
Console.WriteLine("Button 1 Touch Down.");
}
private void button2_TouchDown(object sender, TouchEventArgs e)
{
Console.WriteLine("Button 2 Touch Down.");
}
}
When I perform a single touch on either button it fires as expected, the TouchDown event, and Click event along with the button animation occur.
However, when I attempt to do two touches simultaneously (one finger held down, another one pressing), the TouchDown events get fired but the the Click events and the button animations do not happen.
It clearly registers the touch points but I don't understand why it doesn't perform actions/events to the WPF controls when touches happen simultaneously.
Any help or direction would be appreciated.

I think thats because the old version of Click event is not prepared well for a multi-touch wpf application. It is primary classified as a mouse event, since the TouchDown is touch event primary so it support the multi-touch feature.

Related

UIElement.ManipulationDelta only Triggers Once on C# WPF

I want to implement an UI for finger controling, in WPF C# .Net framework, VS2019.
ManipulationDelta event is added on a Rectangle and it supposed to work continiously. But when I test it, it triggered only once at the moment I tapped(touch down). This event should be triggered continuously while my finger pressing.
Target: Show the position of pointer within the rectangle area.
XAML:
<Window x:Class="WpfApp5.MainWindow"
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"
xmlns:local="clr-namespace:WpfApp5"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid Margin="0,0,-322,-112">
<Rectangle
ManipulationDelta="Rectangle_ManipulationDelta"
TouchMove="Rectangle_TouchMove"
Fill="#FFF4F4F5"
HorizontalAlignment="Left"
Height="274" Margin="162,70,0,0"
Stroke="Black"
VerticalAlignment="Top"
Width="582" IsManipulationEnabled="True"/>
<TextBlock
x:Name="textBlock"
HorizontalAlignment="Left"
TextWrapping="Wrap"
VerticalAlignment="Top"
Margin="31,26,0,0"><Run Text="TextBlock"/></TextBlock>
</Grid>
Here is the event to print the postion of finger:
C#:
namespace WpfApp5{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Rectangle_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
{
}
private void Rectangle_TouchMove(object sender, TouchEventArgs e)
{
textBlock.Text = "Manipulation Touch: " + Mouse.GetPosition(Application.Current.MainWindow).ToString();
}
}
}
UI tested on Windows10 Simulator v16 and Surface Pro
Holding right-clicking is disabled
A test video is here to describe the issue with subtitle
Test Video
After testing, the event likes TouchMove, MouseMove, ManipulationDelta will be fired only if the cursor "get into" the border of element. I want to trigger this event within target area. Or should I use another event to achieve this?
Any suggestion is appreciated! Thank you.
I found that I use worng event, I should use TouchMove instead of ManipulationDelta(manipulation means manipulation for translation, zoom, etc, it's not necessary in this case).
And the flag should be set to false:
IsManipulationEnabled="false"
It working now! And thanks for who paticipating this discussion.

WPF call Window_Closing event from code behind

Recently I have been experimenting with WPF. I was building a little program, but then I stumbled across a little problem. I tried to call the Window_Closing method from the code behind, it told me that I needed to give it cerntain parameters, but I don't have those parameters in the method I am trying to call it from.
This is my code:
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
// My Window Closing code
}
private void Application_Exit(object sender, RoutedEventArgs e)
{
// Here is where I am trying to call it, giving a empty parameter with it.
// But it doesn't seem to work.
Window_Closing(null, EventArgs.Empty)
}
What I want
If a cenrtain button is called, I want the Window_Closing event to be called.
Anyone who knows the solution?
In your Designer, click on the Button and open its property window. There you select the "Events" - the "lightning" and choose the Click event to execute your Window_Closing method. There is a drop down in which you should be able to select it. If not, enter your method name there and press "Enter" to let VS generate the code-behind method.
Add "Window_Closing" & "Close_Click" in the XAML file (MainWindow.xaml) as follows.
<Window x:Class="WpfApp1.MainWindow"
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"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800" Closing="Window_Closing">
<Grid>
<Button x:Name="Close" Content="Close" Click="Close_Click" Width="100" Height="30"/>
</Grid>
Then in the code behind file (MainWindow.xaml.cs) add the following code. Here the window close command is called from the button click event handler which in turn closes the window, and then the 'Window_Closing' event handler will be automatically called.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
}
private void Close_Click(object sender, RoutedEventArgs e)
{
Close();
}
}
Just close the window. Then the event will be called automatically, thats what it is there for to begin with.
And as it seems, you try calling it from your Application_Exit, which closes all the windows ... so .... What is your problem?
Just put a breakpoint in the Window_Closing and see, that is executed automatically. If not, maybe you should add the eventhander to all the windows Window_Closing events.

MouseEnter event does not fire on a Popup control after a mouse click on the Control

I was testing a Popup control in WPF with the following code
<Window x:Class="Popup1.MainWindow"
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"
xmlns:local="clr-namespace:Popup1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="250">
<Grid>
<TextBlock TextWrapping="Wrap">You can use a popup to provide a link for a specific
<Run TextDecorations="Underline" MouseEnter="ContentElement_OnMouseEnter">
term
</Run>
</TextBlock>
<Popup Name="popLink" StaysOpen="False" Placement="Mouse" MaxWidth="200"
PopupAnimation="Slide" AllowsTransparency="True">
<Border>
<TextBlock Margin="10" TextWrapping="Wrap">
For more information, see
<Hyperlink NavigateUri="http://en.wikipedia.org/wiki/Term" Click="Hyperlink_OnClick">Wikipedia</Hyperlink>
</TextBlock>
</Border>
</Popup>
</Grid>
</Window>
and the handlers
private void ContentElement_OnMouseEnter(object sender, MouseEventArgs e) {
popLink.IsOpen = true;
}
private void Hyperlink_OnClick(object sender, RoutedEventArgs e) {
Process.Start(((Hyperlink) sender).NavigateUri.ToString());
}
The result is a trivial window that contains a textblock with a link to a popup control that visually appears when the mouse hovers over the link to the popup.
The normal behavioris the popup to stay visible until a mouse click. This works fine as long as the mouse click is not on the link to the popup
The strange behaviorthat i can't explain happens when i click the mouse over the link to the popup.Then, the popup closes ( as expected ) but it never appears again when the mouse hovers over the link (as it should).
Can you explain this behavior?
As commented, the reason is probably a race condition between closing popup and re-opening because the mouse is over the textblock. You can prevent this situation by delaying the popup open action until current work is completed:
private void ContentElement_OnMouseEnter(object sender, MouseEventArgs e)
{
Dispatcher.BeginInvoke(new Action(() => popLink.IsOpen = true));
}
Regarding your title text: the MouseEnter event is actually fired (debug it!), just the action within is not working as expected because the popup is in an inconsistent state.
After some tweaking the best behaviour is achieved if we add an extra event (comparing to the initial code) handler for the Popup Close event that sets the IsOpen property to false when the popup closes
private void PopLink_OnClosed(object sender, EventArgs e) {
if (popLink.IsOpen) {
popLink.IsOpen = false;
}
}
and the ammenment in XAML
<Popup Name="popLink" StaysOpen="False" Placement="Mouse" MaxWidth="200"
PopupAnimation="Slide" AllowsTransparency="True"
Closed="PopLink_OnClosed">
<Border Background="Bisque">
<TextBlock Margin="10" TextWrapping="Wrap">
For more information, see
<Hyperlink NavigateUri="http://en.wikipedia.org/wiki/Term" Click="Hyperlink_OnClick">Wikipedia</Hyperlink>
</TextBlock>
</Border>
</Popup>

Paint event does not fire when Invalidate() is called

I am working on a WPF application that has a Panel within a WindowsFormHost. The panel contains graphics that need to be redrawn every so often, and the code that draws these graphics is located within an OnPaint() event. The problem is, the OnPaint() event never seems to fire. To debug, I added a button to my form and used the button's click event handler to call the Invalidate() event. Even when I call Invalidate(), I can't seem to get the Paint event to fire. My code-behind looks like this:
public MainWindow()
{
InitializeComponent();
}
private void myPanel_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
/// Draw stuff
}
private void Button_Click(object sender, RoutedEventArgs e)
{
myPanel.Invalidate();
}
And my XAML looks like this:
<Window x:Class="MyProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel Name="stackPanel">
<Button Content="Button" Click="Button_Click"/>
<WindowsFormsHost x:Name="windowsFormsHost" >
<WindowsFormsHost.Child>
<wf:Panel x:Name="myPanel" Paint="myPanel_Paint"/>
</WindowsFormsHost.Child>
</WindowsFormsHost>
</StackPanel>
</Grid>
I've read through this: WindowsFormHost Paint Event Not Firing
...but we don't seem to be having the same problem, as my XAML does reference my Paint event handler, and OnPaint() still doesn't fire.
I have already tried adding myPanel.Update() to my Button_Click event, beneath my call to myPanel.Invalidate(). That also doesn't work.
What am I doing wrong here? Is it possible that Invalidate() is not really invalidating?

Cannot drag text into a WPF window

I'm trying to set up a WPF window so that it can accept different types of data via Drag and Drop. If I make a new project and set the window to the following:
<Window x:Class="DropShare.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300" AllowDrop="True" DragEnter="Window_DragEnter">
<Grid>
</Grid>
</Window>
And set the code-behind to:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void Window_DragEnter(object sender, DragEventArgs e)
{
}
}
I only ever get DragEnter firing for files. It never fires for anything else - text, images, etc.
Is there something I'm missing? All the tutorials I've read have seemed to suggest this is all that's needed as the DragEnter event handler let's me state what I accept.
So your code works fine for me. But try this...
In your Window:
<Label Background="Purple" HorizontalAlignment="Center" VerticalAlignment="Center" Content="Drag from here!" MouseDown="Label_MouseDown"/>
and in your code behind:
private void Label_MouseDown(object sender, MouseButtonEventArgs e)
{
DragDrop.DoDragDrop(this, "This is just a test", DragDropEffects.All);
}
Then drag from the label into the window and see if your event fires.
If this works, it may have something to do with the permissions level between Visual Studio and your outside environment (possibly).
See:
https://superuser.com/questions/59051/drag-and-drop-file-into-application-under-run-as-administrator
In WPF drag and drop feature always has to deal with DragDrop Class, Please check here how to do drag and drop across applications

Categories