WPF 已知問題 開啓 IsManipulationEnabled 之後觸摸長按 RepeatButton 不會觸發連續的 Click 事件

本文記錄 WPF 的一個已知問題,在 RepeatButton 上開啓 IsManipulationEnabled 漫遊支持之後,將會導致觸摸長按到 RepeatButton 之上時,不會收到源源不斷的 Click 事件

這是有個夥伴在 WPF 官方倉庫報告的問題,詳細請看 https://github.com/dotnet/wpf/issues/8223

原始的問題是他發現放在 ListBox 裏面的 RepeatButton 無法在觸摸長按的時候收到連續的 Click 事件,以爲是放在 ListBox 下的 RepeatButton 存在奇怪的問題

實際上他的這個問題和 ListBox 沒有任何關係,僅僅只是因爲開啓了 IsManipulationEnabled 之後,爲了實現觸摸的漫遊,無法實時提升觸摸爲鼠標,從而導致了使用鼠標事件的 RepeatButton 無法觸發源源不斷的 Click 事件

這裏的 IsManipulationEnabled 屬性影響指的是在 RepeatButton 以及 RepeatButton 所在的上層容器控件裏面設置都會影響到此行爲,換句話說只要 RepeatButton 或 RepeatButton 所在的上層容器控件裏面設置 IsManipulationEnabled 都能復現 RepeatButton 在觸摸長按時無法收到源源不斷的 Click 事件

在 ListBox 裏面實際上隱藏了包含 IsManipulationEnabled 爲 true 的 ScrollViewer 控件,只需將其 IsManipulationEnabled 屬性設置爲 false 就能繼續讓 RepeatButton 在觸摸長按時不斷觸發 Click 事件,如下面代碼例子,以下是 XAML 部分的代碼,可以看到只是簡單在 ListBox 裏面放入一個 RepeatButton 控件

<ListBox x:Name="ListBox" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch">
    <ListBoxItem>
        <RepeatButton Height="100" Click="ListBoxRepeatButtonClick" Content="Long touch 'repeat' not working on this RepeatButton"/>
    </ListBoxItem>
</ListBox>

此時如果直接運行代碼,觸摸長按 RepeatButton 按鈕,將發現 Click 事件不會源源不斷觸發。接下來測試將 ListBox 裏面的 ScrollViewer 控件的 IsManipulationEnabled 屬性設置爲 false 後的對 RepeatButton 的觸摸長按,修改代碼如下

        public MainWindow()
        {
            InitializeComponent();
            Loaded += MainWindow_Loaded;
        }

        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            if (GetChild(ListBox, o => o is ScrollViewer) is ScrollViewer scrollViewer)
            {
                scrollViewer.IsManipulationEnabled = false;
            }
        }

        private object? GetChild(DependencyObject root, Func<object, bool> predicate)
        {
            var childrenCount = VisualTreeHelper.GetChildrenCount(root);
            for (var i = 0; i < childrenCount; i++)
            {
                var child = VisualTreeHelper.GetChild(root,i);
                if (predicate(child))
                {
                    return child;
                }
                else if (child is DependencyObject dependencyObject)
                {
                    var result = GetChild(dependencyObject, predicate);
                    if (result != null)
                    {
                        return result;
                    }
                }
            }

            return null;
        }

以上代碼通過視覺樹(可視化樹)找到 ListBox 裏面 ScrollViewer 控件,將其 IsManipulationEnabled 屬性設置爲 false 從而讓 RepeatButton 不再放入到任何包含 IsManipulationEnabled 爲 true 的容器內,運行代碼,此時可以看到放入到 ListBox 的 RepeatButton 能夠在觸摸長按時不斷收到 Click 事件

由於此問題是 WPF 層爲了實現觸摸下的漫遊,從而禁用了提升鼠標,我閱讀了代碼發現除非來一次重構否則怎麼修都是打補丁,預計很長時間都不會解決這個問題

本文以上代碼放在githubgitee 歡迎訪問

可以通過如下方式獲取本文的源代碼,先創建一個空文件夾,接着使用命令行 cd 命令進入此空文件夾,在命令行裏面輸入以下代碼,即可獲取到本文的代碼

git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin b7b624200bcf8ff4797c25c5ee8961b698324670

以上使用的是 gitee 的源,如果 gitee 不能訪問,請替換爲 github 的源。請在命令行繼續輸入以下代碼

git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin b7b624200bcf8ff4797c25c5ee8961b698324670

獲取代碼之後,進入 GejidebedaicifeCalnelehehar 文件夾

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章