本文記錄 Avalonia 11.1 版本的已知問題,在 Linux 上使用 X11 時,在應用啟動時,即使在 Loaded 或 Activated 事件裡,都無法使用 PointToScreen 獲取到正確的螢幕座標,只會將傳入的點作為返回值
此問題已經報告給 Avalonia 官方,請看 https://github.com/AvaloniaUI/Avalonia/issues/16622
如以下程式碼所示
public MainWindow()
{
InitializeComponent();
Loaded += MainWindow_Loaded;
Activated += MainWindow_Activated;
}
private void MainWindow_Activated(object? sender, EventArgs e)
{
var pointToScreen = this.PointToScreen(new Point(0, 0));
Console.WriteLine($"MainWindow_Activated PointToScreen={pointToScreen}");
}
private void MainWindow_Loaded(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
var pointToScreen = this.PointToScreen(new Point(0, 0));
Console.WriteLine($"MainWindow_Loaded PointToScreen={pointToScreen}");
}
將以上程式碼執行在 X11 上,將無法在 Loaded 或 Activated 事件裡使用 PointToScreen 獲取到正確的螢幕座標
執行以上程式碼在 X11 上將會在控制檯有以下資訊
MainWindow_Loaded PointToScreen=0, 0
MainWindow_Activated PointToScreen=0, 0
如果此時在 MainWindow_Loaded
新增 Task.Delay 一秒即可拿到正確的螢幕座標
private async void MainWindow_Loaded(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
var pointToScreen = this.PointToScreen(new Point(0, 0));
Console.WriteLine($"MainWindow_Loaded PointToScreen={pointToScreen}"); // It can not get the correct coordinates here!
await Task.Delay(1000);
pointToScreen = this.PointToScreen(new Point(0, 0));
Console.WriteLine(pointToScreen); // It can get the correct coordinates.
}
以上問題我在 UOS 統信系統和 Kylin 麒麟系統上都進行測試,且透過分析程式碼可以瞭解到此問題與系統沒有相關性。即不是 UOS 統信系統和 Kylin 麒麟系統挖的坑
此問題原因是在 Avalonia 裡面依賴當前視窗座標進行 PointToScreen 的計算,而座標是在 X11 的 ConfigureNotify 事件裡面更新的,這就意味著在視窗 Loaded 或 Activated 事件裡還沒有完成座標的更新,從而導致無法正確計算螢幕座標
由於視窗座標更新將會觸發 PositionChanged 事件,如果想要規避此問題,可以將在 Loaded 事件執行的 PointToScreen 方法嘗試更改為 PositionChanged 執行,如下面程式碼
public MainWindow()
{
InitializeComponent();
PositionChanged += MainWindow_PositionChanged;
}
private void MainWindow_PositionChanged(object? sender, PixelPointEventArgs e)
{
var pointToScreen = this.PointToScreen(new Point(0, 0));
Console.WriteLine($"PositionChanged PointToScreen={pointToScreen}");
}
必須說明的是 PositionChanged 和 Loaded 是完全不相同的時機,還請大家根據自己的業務進行修改
本文程式碼放在 github 和 gitee 上,可以使用如下命令列拉取程式碼。我整個程式碼倉庫比較龐大,使用以下命令列可以進行部分拉取,拉取速度比較快
先建立一個空資料夾,接著使用命令列 cd 命令進入此空資料夾,在命令列裡面輸入以下程式碼,即可獲取到本文的程式碼
git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 7036c43bcea5d9057dcddfea7ff3ef7aae84dc07
以上使用的是國內的 gitee 的源,如果 gitee 不能訪問,請替換為 github 的源。請在命令列繼續輸入以下程式碼,將 gitee 源換成 github 源進行拉取程式碼。如果依然拉取不到程式碼,可以發郵件向我要程式碼
git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin 7036c43bcea5d9057dcddfea7ff3ef7aae84dc07
獲取程式碼之後,進入 AvaloniaIDemo/JejanayaYemjergayle 資料夾,即可獲取到原始碼
更多 Avalonia 相關部落格,請參閱 部落格導航