diff --git a/MainPage.xaml b/MainPage.xaml
index f38dd28..0c0e962 100644
--- a/MainPage.xaml
+++ b/MainPage.xaml
@@ -27,22 +27,22 @@
LineBreakMode="MiddleTruncation" />
-
-
-
+
+
-
-
-
+
+
LeftItems { get; } = new();
public ObservableCollection RightItems { get; } = new();
private string _leftPath = string.Empty;
private string _rightPath = string.Empty;
+ // Для управления выделением и фокусом
+ private Button? _currentFocusedButton;
+ private bool _isLeftPanelActive = true;
+ private int _leftSelectedIndex = -1;
+ private int _rightSelectedIndex = -1;
+
public string LeftPath
{
get => _leftPath;
@@ -48,111 +53,195 @@ public partial class MainPage : ContentPage, INotifyPropertyChanged
private FileSystemItem? _selectedLeftItem;
private FileSystemItem? _selectedRightItem;
+ // Для двойного нажатия
+ private FileSystemItem? _lastClickedItem;
+ private bool? _lastIsLeftPanel;
+
public MainPage(IFileSystemService fileService)
{
InitializeComponent();
_fileService = fileService;
BindingContext = this;
+ // Инициализация шаблонов
+ InitializeCollectionViews();
+
var root = _fileService.GetRootPath();
LoadDirectory(root, true);
LoadDirectory(root, false);
+
+ // Устанавливаем фокус на страницу
+ this.Focus();
}
- private void LoadDirectory(string path, bool isLeft)
+ private void InitializeCollectionViews()
{
- var items = _fileService.GetDirectoryContents(path).ToList();
- var panel = isLeft ? LeftPanel : RightPanel;
- var targetItems = isLeft ? LeftItems : RightItems;
- var currentPathProperty = isLeft ? nameof(_currentLeftPath) : nameof(_currentRightPath);
+ LeftPanel.ItemTemplate = PanelCollectionView.CreateItemTemplate(isLeftPanel: true, page: this);
+ RightPanel.ItemTemplate = PanelCollectionView.CreateItemTemplate(isLeftPanel: true, page: this);
+ }
- // Очистка панели
- panel.Clear();
- targetItems.Clear();
- // Заполнение
- foreach (var item in items)
- {
- targetItems.Add(item);
+ protected override void OnHandlerChanged()
+ {
+ base.OnHandlerChanged();
+ this.Focus();
+ }
- var button = new Button
+ public void HandleItemClick(FileSystemItem item, bool isLeftPanel)
+ {
+ if (_lastIsLeftPanel == isLeftPanel && _lastClickedItem == item)
+ {
+ // Двойной клик
+ if (isLeftPanel)
+ OnLeftItemDoubleTapped(item);
+ else
+ OnRightItemDoubleTapped(item);
+ }
+ else
+ {
+ // Одинарный клик - выделение
+ if (isLeftPanel)
{
- Text = item.DisplayText,
- TextColor = Colors.Black,
- Padding = new Thickness(10),
- HeightRequest = 40,
- BackgroundColor = Colors.Transparent,
- BorderWidth = 0,
- CommandParameter = item
- };
-
- button.Clicked += isLeft ? OnLeftItemActivated : OnRightItemActivated;
-
- // Добавляем визуальные состояния
- var normal = new VisualState { Name = "Normal" };
- var focused = new VisualState { Name = "Focused" };
- focused.Setters.Add(new Setter { Property = Button.BorderColorProperty, Value = Colors.Black });
- focused.Setters.Add(new Setter { Property = Button.BorderWidthProperty, Value = 2 });
-
- var pressed = new VisualState { Name = "Pressed" };
- pressed.Setters.Add(new Setter { Property = Button.BackgroundColorProperty, Value = Color.FromArgb("#e0e0e0") });
-
- var commonStates = new VisualStateGroup { Name = "CommonStates" };
- commonStates.States.Add(normal);
- commonStates.States.Add(focused);
- commonStates.States.Add(pressed);
-
- var groups = new VisualStateGroupList();
- groups.Add(commonStates);
-
- VisualStateManager.SetVisualStateGroups(button, groups);
-
- panel.Add(button);
+ _isLeftPanelActive = true;
+ _leftSelectedIndex = LeftItems.IndexOf(item);
+ _selectedLeftItem = item;
+ _selectedRightItem = null;
+ }
+ else
+ {
+ _isLeftPanelActive = false;
+ _rightSelectedIndex = RightItems.IndexOf(item);
+ _selectedRightItem = item;
+ _selectedLeftItem = null;
+ }
+ UpdateVisualSelection();
}
+ _lastIsLeftPanel = isLeftPanel;
+ _lastClickedItem = item;
+ }
+
+ private void LoadDirectory(string path, bool isLeft)
+ {
+ var items = _fileService.GetDirectoryContents(path).ToList();
- // Обновление пути
if (isLeft)
{
+ LeftItems.Clear();
+ foreach (var item in items) LeftItems.Add(item);
_currentLeftPath = path;
LeftPath = path;
+
+ // Сбрасываем выделение при загрузке новой директории
+ _leftSelectedIndex = items.Count > 0 ? 0 : -1;
}
else
{
+ RightItems.Clear();
+ foreach (var item in items) RightItems.Add(item);
_currentRightPath = path;
RightPath = path;
+
+ _rightSelectedIndex = items.Count > 0 ? 0 : -1;
}
+
+ UpdateVisualSelection();
}
- private void OnLeftItemActivated(object sender, EventArgs e)
+ // Обработчики выделения (вызываются при изменении Selection в CollectionView)
+ private void OnLeftSelectionChanged(object sender, SelectionChangedEventArgs e)
{
- var button = (Button)sender;
- var item = (FileSystemItem)button.CommandParameter;
+ // Обновляем индексы при программном изменении selection
+ if (e.CurrentSelection.FirstOrDefault() is FileSystemItem selectedItem)
+ {
+ _leftSelectedIndex = LeftItems.IndexOf(selectedItem);
+ _isLeftPanelActive = true;
+ UpdateVisualSelection();
+ }
+ }
- _selectedLeftItem = item;
- _selectedRightItem = null;
+ private void OnRightSelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ if (e.CurrentSelection.FirstOrDefault() is FileSystemItem selectedItem)
+ {
+ _rightSelectedIndex = RightItems.IndexOf(selectedItem);
+ _isLeftPanelActive = false;
+ UpdateVisualSelection();
+ }
+ }
- if (item.IsDirectory)
+ private void UpdateVisualSelection()
+ {
+ //Сбрасываем предыдущий фокус
+ if (_currentFocusedButton != null)
{
- LoadDirectory(item.FullName, true);
+ VisualStateManager.GoToState(_currentFocusedButton, "Normal");
+ _currentFocusedButton = null;
+ }
+
+ if (_isLeftPanelActive && _leftSelectedIndex >= 0 && _leftSelectedIndex < LeftItems.Count)
+ {
+ var item = LeftItems[_leftSelectedIndex];
+ SetFocusToItem(LeftPanel, item);
+ _selectedLeftItem = item;
+ _selectedRightItem = null;
+ }
+ else if (!_isLeftPanelActive && _rightSelectedIndex >= 0 && _rightSelectedIndex < RightItems.Count)
+ {
+ var item = RightItems[_rightSelectedIndex];
+ SetFocusToItem(RightPanel, item);
+ _selectedRightItem = item;
_selectedLeftItem = null;
}
}
- private void OnRightItemActivated(object sender, EventArgs e)
+ private void SetFocusToItem(CollectionView collectionView, FileSystemItem item)
{
- var button = (Button)sender;
- var item = (FileSystemItem)button.CommandParameter;
+ // Используем Dispatcher чтобы дождаться рендеринга
+ Dispatcher.Dispatch(() =>
+ {
+ var container = FindButtonContainer(collectionView, item);
+ if (container is Button button)
+ {
+ VisualStateManager.GoToState(button, "Focused");
+ _currentFocusedButton = button;
+ _lastClickedItem = item;
- _selectedRightItem = item;
- _selectedLeftItem = null;
+ // Прокручиваем к выбранному элементу
+ collectionView.ScrollTo(item, position: ScrollToPosition.MakeVisible, animate: false);
+ }
+ });
+ }
+ private Button? FindButtonContainer(CollectionView collectionView, FileSystemItem item)
+ {
+ // Ищем кнопку в логических дочерних элементах
+ foreach (var child in collectionView.LogicalChildren)
+ {
+ if (child is Button button && button.BindingContext == item)
+ {
+ return button;
+ }
+ }
+ return null;
+ }
+
+ public void OnLeftItemDoubleTapped(FileSystemItem item)
+ {
+ if (item.IsDirectory)
+ {
+ LoadDirectory(item.FullName, true);
+ }
+ }
+
+ public void OnRightItemDoubleTapped(FileSystemItem item)
+ {
if (item.IsDirectory)
{
LoadDirectory(item.FullName, false);
- _selectedRightItem = null;
}
}
+ // Остальные методы без изменений
private async void OnCopyClicked(object sender, EventArgs e)
{
await ProcessFileOperation(async (src, destDir) =>
diff --git a/PanelCollectionView.cs b/PanelCollectionView.cs
new file mode 100644
index 0000000..7c7b9b0
--- /dev/null
+++ b/PanelCollectionView.cs
@@ -0,0 +1,59 @@
+using Microsoft.Maui.Controls;
+
+namespace CommanderApp;
+
+public static class PanelCollectionView
+{
+ public static DataTemplate CreateItemTemplate(bool isLeftPanel, MainPage page)
+ {
+ return new DataTemplate(() =>
+ {
+ var button = new Button
+ {
+ Padding = new Thickness(15, 8, 5, 8), // left, top, right, bottom
+ HeightRequest = 40,
+ BackgroundColor = Colors.Transparent,
+ BorderWidth = 0,
+ TextColor = Colors.Black,
+ HorizontalOptions = LayoutOptions.Fill,
+ };
+
+ button.SetBinding(Button.TextProperty, new Binding("DisplayText"));
+ button.SetBinding(Button.CommandParameterProperty, new Binding("."));
+
+ // Обработчик нажатия
+ button.Clicked += (s, e) =>
+ {
+ if (s is Button btn && btn.CommandParameter is FileSystemItem item)
+ {
+ page.HandleItemClick(item, isLeftPanel);
+ }
+ };
+
+ // Визуальные состояния для фокуса
+ var visualStateGroups = new VisualStateGroupList();
+ var commonStates = new VisualStateGroup { Name = "CommonStates" };
+
+ var normalState = new VisualState { Name = "Normal" };
+ normalState.Setters.Add(new Setter { Property = Button.TextColorProperty, Value = Colors.Black });
+
+ var focusedState = new VisualState { Name = "Focused" };
+ focusedState.Setters.Add(new Setter { Property = Button.BorderColorProperty, Value = Colors.Blue });
+ focusedState.Setters.Add(new Setter { Property = Button.BorderWidthProperty, Value = 2 });
+
+ var pressedState = new VisualState { Name = "Pressed" };
+ pressedState.Setters.Add(new Setter { Property = Button.TextColorProperty, Value = Colors.Black });
+ pressedState.Setters.Add(new Setter { Property = Button.BackgroundColorProperty, Value = Color.FromArgb("#e0e0e0") });
+
+ commonStates.States.Add(normalState);
+ commonStates.States.Add(focusedState);
+ //commonStates.States.Add(pressedState);
+ visualStateGroups.Add(commonStates);
+
+ VisualStateManager.SetVisualStateGroups(button, visualStateGroups);
+
+ return button;
+ });
+ }
+
+}
\ No newline at end of file