Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF / C# - Dialog Window doesn't respond to Touch

I'm developing a C# WPF application that is intended to run on full Windows 10 tablets using exclusively touch. So far, the app works great, except for one of my dialog windows has buttons that don't like to be touched.

Dialog Window XAML:

<Window x:Class="Commencement_Organizer.ConfirmStudentWindow"
    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:Commencement_Organizer"
    mc:Ignorable="d"
    Title="Confirmation" Topmost="True" Height="372.677" Width="578.225" ResizeMode="NoResize" WindowStartupLocation="CenterScreen" 
    WindowStyle="None" Background="White" AllowsTransparency="True" Stylus.IsTapFeedbackEnabled="False" Stylus.IsTouchFeedbackEnabled="False">

<Window.Triggers>
    <EventTrigger RoutedEvent="Window.Loaded">
        <BeginStoryboard>
            <Storyboard>
                <DoubleAnimation Duration="00:00:0.2" Storyboard.TargetProperty="Opacity" From="0" To="1" />
            </Storyboard>
        </BeginStoryboard>
    </EventTrigger>
</Window.Triggers>

<Grid Background="#FF171717">
    <Grid Margin="1" Background="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>

        <Button x:Name="YesButton" Content="Yes" Margin="25" Grid.Row="2" Click="YesButton_Click"/>
        <Button x:Name="NoButton" Content="No" Margin="25" Grid.Row="2" Grid.Column="1" Click="NoButton_Click"/>
        <Label x:Name="label" Content="Confirm your name" Margin="0" Grid.ColumnSpan="2" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="24"/>
        <Label x:Name="nameLabel" Content="Label" HorizontalAlignment="Center" Margin="0" Grid.Row="1" VerticalAlignment="Center" Grid.ColumnSpan="2" FontSize="24" FontWeight="Bold"/>

    </Grid>
</Grid>

Implementation (C#):

ConfirmStudentWindow confirmWindow = new ConfirmStudentWindow(student);
        confirmWindow.Confirm += OnConfirm;

        // This window makes everything behind the dialog window a grey tint, which makes the dialog more prominent
        var darkwindow = new Window() 
        {
            Background = Brushes.Black,
            Opacity = 0.4,
            AllowsTransparency = true,
            WindowStyle = WindowStyle.None,
            WindowState = WindowState.Maximized,
            Topmost = true,
            Effect = new BlurEffect()
        };
        darkwindow.Show(); // Show grey background tint
        confirmWindow.ShowDialog(); // Stops main UI thread
        darkwindow.Close();

Everything about this works as intended, except when I try to use a touchscreen to use those buttons, they just stay highlighted, but don't actually click. Works perfect with a mouse.

Tested on 2 different Windows 10 Devices (Surface Pro 2 and Surface Book).

To put it in the form of a question:

Why does launching this window as a Dialog make it resistant to touch, but not if it's launched as a regular window?

Edit - New Question:

Is there any way to simulate a Dialog window other than launching a regular window that always stays on top and then put a tinted overlay behind it while giving the window an eventhandler that provides the result of the user input?

like image 899
Clay07g Avatar asked Oct 29 '22 19:10

Clay07g


2 Answers

I tried your example and it is running without any problem at my end. I am using DELL notebook with touch display with W10 and .NET 4.5.2. One thing that I can suggest you is to try to hook up StylusUp (or StylusDown that depends on your logic) event on buttons in dialog. I did encounter similar problems in the past when only click event was managed.

This worked for me, confirm method was called and dialog closed.

ConfirmStudentWindow.xaml.cs

using System;
using System.Windows;
using System.Windows.Input;

namespace DialogTouchTest
{
    /// <summary>
    /// Interaction logic for ConfirmStudentWindow.xaml
    /// </summary>
    public partial class ConfirmStudentWindow : Window
    {
        public Action Confirm;

        public ConfirmStudentWindow()
        {
            InitializeComponent();
        }

        private void YesButton_Click(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            Yes();
        }

        private void NoButton_Click(object sender, RoutedEventArgs e)
        {
            e.Handled = true;
            No();
        }

        private void YesButton_StylusUp(object sender, StylusEventArgs e)
        {
            e.Handled = true;
            Yes();
        }

        private void NoButton_StylusUp(object sender, StylusEventArgs e)
        {
            e.Handled = true;
            No();
        }

        private void Yes()
        {
            DialogResult = true;
            Confirm();
        }

        private void No()
        {
            DialogResult = false;
        }
    }
}

ConfirmStudentWindow.xaml

<Window x:Class="DialogTouchTest.ConfirmStudentWindow"
        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"
    Title="Confirmation" Topmost="True" Height="372.677" Width="578.225" ResizeMode="NoResize" WindowStartupLocation="CenterScreen" 
    WindowStyle="None" Background="White" AllowsTransparency="True" Stylus.IsTapFeedbackEnabled="False" Stylus.IsTouchFeedbackEnabled="False">

    <Window.Triggers>
        <EventTrigger RoutedEvent="Window.Loaded">
            <BeginStoryboard>
                <Storyboard>
                    <DoubleAnimation Duration="00:00:0.2" Storyboard.TargetProperty="Opacity" From="0" To="1" />
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Window.Triggers>

    <Grid Background="#FF171717">
        <Grid Margin="1" Background="White">
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
                <RowDefinition Height="*" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>

            <Button x:Name="YesButton" Content="Yes" Margin="25" Grid.Row="2" StylusUp="YesButton_StylusUp" Click="YesButton_Click"/>
            <Button x:Name="NoButton" Content="No" Margin="25" Grid.Row="2" Grid.Column="1" StylusUp="NoButton_StylusUp" Click="NoButton_Click"/>
            <Label x:Name="label" Content="Confirm your name" Margin="0" Grid.ColumnSpan="2" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="24"/>
            <Label x:Name="nameLabel" Content="Label" HorizontalAlignment="Center" Margin="0" Grid.Row="1" VerticalAlignment="Center" Grid.ColumnSpan="2" FontSize="24" FontWeight="Bold"/>

        </Grid>
    </Grid>
</Window>

MainWindow.xaml.cs

using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Effects;

namespace DialogTouchTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void button_Click(object sender, RoutedEventArgs e)
        {
            ConfirmStudentWindow confirmWindow = new ConfirmStudentWindow();
            confirmWindow.Confirm += OnConfirm;

            // This window makes everything behind the dialog window a grey tint, which makes the dialog more prominent
            var darkwindow = new Window()
            {
                Background = Brushes.Black,
                Opacity = 0.4,
                AllowsTransparency = true,
                WindowStyle = WindowStyle.None,
                WindowState = WindowState.Maximized,
                Topmost = true,
                Effect = new BlurEffect()
            };
            darkwindow.Show(); // Show grey background tint
            confirmWindow.ShowDialog(); // Stops main UI thread
            darkwindow.Close();
        }

        private void OnConfirm()
        {

        }
    }
}
like image 94
benderto Avatar answered Nov 15 '22 04:11

benderto


Comparing two identical .Show() methods, one being executed from a ViewModel and the other executed in code-behind, I found that the code-behind instance did not detect touches.

My solution was to invoke the method on the main UI thread from code-behind:

Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() =>
{
     window.Show()
}));

Beware that if you expect a result from the dialog then you will need to include it within the `Dispatched.BeginInvoke' method, otherwise it will not work correctly.

Ideally, grouping all relevant logics within would be the best approach.

like image 20
Jack Avatar answered Nov 15 '22 06:11

Jack