本文記錄 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 層爲了實現觸摸下的漫遊,從而禁用了提升鼠標,我閱讀了代碼發現除非來一次重構否則怎麼修都是打補丁,預計很長時間都不會解決這個問題
可以通過如下方式獲取本文的源代碼,先創建一個空文件夾,接着使用命令行 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 文件夾