using Avalonia.Controls; using Avalonia.Interactivity; using Avalonia.Platform.Storage; using Avalonia.Threading; using AI.ViewModels; namespace AI.Views { public partial class MainWindow : Window { private bool _isUserAtBottom = true; // 跟踪用户是否在底部 private const double ScrollThreshold = 50.0; // 距离底部的阈值(像素) public MainWindow() { InitializeComponent(); DataContextChanged += MainWindow_DataContextChanged; } private void MainWindow_DataContextChanged(object? sender, EventArgs e) { if (DataContext is MainWindowViewModel vm) { vm.RequestScrollToBottom += ViewModel_RequestScrollToBottom; // 订阅文件选择请求事件 vm.RequestFileSelection += async () => { var files = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions { Title = "选择文件", AllowMultiple = false, FileTypeFilter = new[] { FilePickerFileTypes.All } }); return files; }; } // 初始化滚动视图的滚动事件监听 if (ChatMessagesScrollViewer != null) { ChatMessagesScrollViewer.ScrollChanged += ChatMessagesScrollViewer_ScrollChanged; } } private void ChatMessagesScrollViewer_ScrollChanged(object? sender, ScrollChangedEventArgs e) { if (sender is ScrollViewer scrollViewer) { // 检查用户是否在底部(考虑一个小的阈值,避免浮点数精度问题) var offset = scrollViewer.Offset.Y; var extent = scrollViewer.Extent.Height; var viewport = scrollViewer.Viewport.Height; // 处理边界情况:如果内容高度小于视口高度,认为在底部 if (extent <= viewport) { _isUserAtBottom = true; return; } var distanceFromBottom = extent - (offset + viewport); // 如果距离底部小于阈值,认为用户在底部 _isUserAtBottom = distanceFromBottom <= ScrollThreshold; } } private void ViewModel_RequestScrollToBottom() { Dispatcher.UIThread.InvokeAsync(() => { // 只在用户已经在底部时才自动滚动 // 这样如果用户向上滚动查看历史消息,就不会被强制拉回底部 if (_isUserAtBottom) { ChatMessagesScrollViewer.ScrollToEnd(); } }); } private void OnDeleteSessionClick(object? sender, RoutedEventArgs e) { if (sender is Button button && button.Tag is string sessionId) { if (DataContext is MainWindowViewModel vm) { vm.DeleteSessionCommand.Execute(sessionId); } } } } }