WPF / C# - 对话框窗口无法响应触摸

5

我正在开发一款C# WPF应用程序,旨在在全功能Windows 10平板电脑上使用纯触摸方式运行。目前为止,该应用程序的表现很棒,只是我的一个对话框窗口的按钮不太容易被触摸。

对话框窗口 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>

实现(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();

除了在触摸屏上使用这些按钮时它们只是保持高亮,而不实际点击之外,所有功能都按预期工作。使用鼠标完美无误。
在两个不同的Windows 10设备上进行了测试(Surface Pro 2和Surface Book)。
换句话说:
为什么将此窗口作为对话框启动会使其抵抗触摸,但如果将其作为常规窗口启动则不会?
编辑 - 新问题:
除了启动始终保持在顶部的常规窗口并在其后面放置有色覆盖层并提供用户输入结果的事件处理程序之外,是否有模拟对话框窗口的任何方法?

更新:只有在使用“ShowDialog()”显示窗口时才会出现此错误。 - Clay07g
不用查看你的代码,我记得在.NET中存在一个关于触摸支持的bug。无论如何,最新版本的.NET应该已经修复了这个问题。请参考https://connect.microsoft.com/VisualStudio/feedback/details/903760/wpf-touch-services-are-badly-broken,并尝试使用其中提供的热补丁。 - BudBrot
我会尝试一下。WPF 在触摸方面似乎非常好,除非它是一个对话框窗口。 - Clay07g
1
个人而言,我会避免使用对话框或任何模态窗口。 我只会在显示时覆盖主视图并将其显示出来。 将背景设置为几乎不透明但又不能完全不透明的颜色,这样您就无法通过它进行点击;但它仍然会像您所期望的那样覆盖视图。 还有其他技术,但这种方法很有效。 - Michael Puckett II
这是我最终实现的解决方案,但与 Dialog 相比,它感觉非常臃肿,特别是因为它需要一个事件处理程序来模拟 Dialog 返回。 - Clay07g
我在触摸设备上使用WPF ShowDialog时遇到了问题,请参见我的问题https://dev59.com/t5nga4cB1Zd3GeqPXVqb。NET 4.7承诺解决了这些问题,适用于WPF和触摸设备,详情请参见https://blogs.msdn.microsoft.com/dotnet/2017/04/05/announcing-the-net-framework-4-7/。 - SERWare
2个回答

2
比较两个相同的.Show()方法,一个是从ViewModel执行,另一个是在代码后台执行,我发现代码后台实例不能检测到触摸事件。我的解决方案是从代码后台在主UI线程上调用该方法:
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() =>
{
     window.Show()
}));

请注意,如果您希望从对话框中获得结果,则需要将其包含在“Dispatched.BeginInvoke”方法中,否则它将无法正常工作。

理想情况下,将所有相关逻辑分组在其中是最好的方法。


这是我找到的最佳解决方法,所以谢谢!但我发现在某些情况下它会失败,并且如果你有数据正在进行,它确实会让事情看起来很奇怪。我已经向微软报告了这个错误,请投票支持修复:https://developercommunity.visualstudio.com/content/problem/890778/touch-bugissue-with-showdialog-and-textbox.html - Luishg

1
我尝试了您的示例,它在我的电脑上运行没有任何问题。我使用带有触摸显示屏和W10以及.NET 4.5.2的DELL笔记本电脑。我可以建议您尝试在对话框中的按钮上挂钩StylusUp(或StylusDown,这取决于您的逻辑)事件。过去我遇到了类似的问题,当只管理单击事件时。
这对我有用,确认方法被调用并关闭对话框。

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()
        {

        }
    }
}

我会进行测试并让您知道结果。可能我所需要的只是更新我的.NET Framework。感谢您将我的代码放入独立的示例中,这点加1。如果我能够复制这些结果,我会给您发放奖励的。 - Clay07g
这个程序在我的电脑里似乎也可以正常工作。不过有一个有趣的副作用,就是触摸按钮上方也会激活它们。我相信我可以解决这个问题,只是现在时间不够。但是这个答案确实帮了我很多,谢谢。 - Clay07g

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接