using System.ComponentModel; using FluidExplorer.ViewModels; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Input; namespace FluidExplorer.Views; /// 一个标签页的宿主:负责单/双窗格布局与中间分隔条。 public sealed partial class ExplorerTabView : UserControl { private bool _dragging; private double _startX; private double _startFirstWidth; private double _startSecondWidth; public ExplorerTabView() { InitializeComponent(); Loaded += (_, _) => UpdatePaneLayout(); } public static readonly DependencyProperty TabViewModelProperty = DependencyProperty.Register( nameof(TabViewModel), typeof(ExplorerTabViewModel), typeof(ExplorerTabView), new PropertyMetadata(null, OnTabChanged)); public ExplorerTabViewModel? TabViewModel { get => (ExplorerTabViewModel?)GetValue(TabViewModelProperty); set => SetValue(TabViewModelProperty, value); } private static void OnTabChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var view = (ExplorerTabView)d; if (e.OldValue is ExplorerTabViewModel old) old.PropertyChanged -= view.OnTabPropertyChanged; if (e.NewValue is ExplorerTabViewModel tab) tab.PropertyChanged += view.OnTabPropertyChanged; view.UpdatePaneLayout(); } private void OnTabPropertyChanged(object? sender, PropertyChangedEventArgs e) { if (e.PropertyName == nameof(ExplorerTabViewModel.IsDualPane)) UpdatePaneLayout(); } private void UpdatePaneLayout() { var dual = TabViewModel?.IsDualPane == true; if (dual) { Splitter.Visibility = Visibility.Visible; SecondaryPaneView.Visibility = Visibility.Visible; SplitterColumn.Width = new GridLength(4); if (FirstColumn.Width.IsAbsolute && SecondColumn.Width.IsAbsolute) return; FirstColumn.Width = new GridLength(1, GridUnitType.Star); SecondColumn.Width = new GridLength(1, GridUnitType.Star); } else { Splitter.Visibility = Visibility.Collapsed; SecondaryPaneView.Visibility = Visibility.Collapsed; SplitterColumn.Width = new GridLength(0); FirstColumn.Width = new GridLength(1, GridUnitType.Star); SecondColumn.Width = new GridLength(0); } } private void OnSplitterPointerPressed(object sender, PointerRoutedEventArgs e) { _dragging = true; _startX = e.GetCurrentPoint(LayoutRoot).Position.X; _startFirstWidth = FirstColumn.ActualWidth; _startSecondWidth = SecondColumn.ActualWidth; Splitter.CapturePointer(e.Pointer); } private void OnSplitterPointerMoved(object sender, PointerRoutedEventArgs e) { if (!_dragging) return; var delta = e.GetCurrentPoint(LayoutRoot).Position.X - _startX; var total = _startFirstWidth + _startSecondWidth; const double min = 240; var first = Math.Clamp(_startFirstWidth + delta, min, total - min); FirstColumn.Width = new GridLength(first, GridUnitType.Pixel); SecondColumn.Width = new GridLength(total - first, GridUnitType.Pixel); } private void OnSplitterPointerReleased(object sender, PointerRoutedEventArgs e) { if (!_dragging) return; _dragging = false; Splitter.ReleasePointerCapture(e.Pointer); } }