collection

main
Stepan Pilipenko 4 weeks ago
parent e4511340a9
commit de6eae9d06

@ -27,22 +27,22 @@
LineBreakMode="MiddleTruncation" /> LineBreakMode="MiddleTruncation" />
<!-- Левая панель --> <!-- Левая панель -->
<ScrollView Grid.Row="2" Grid.Column="0"> <CollectionView x:Name="LeftPanel"
<FlexLayout x:Name="LeftPanel" Grid.Row="2" Grid.Column="0"
Padding="0" ItemsSource="{Binding LeftItems}"
Direction="Column" SelectionMode="Single"
JustifyContent="Start" SelectionChanged="OnLeftSelectionChanged"
AlignItems="Start" /> ItemSizingStrategy="MeasureAllItems">
</ScrollView> </CollectionView>
<!-- Правая панель --> <!-- Правая панель -->
<ScrollView Grid.Row="2" Grid.Column="1"> <CollectionView x:Name="RightPanel"
<FlexLayout x:Name="RightPanel" Grid.Row="2" Grid.Column="1"
Padding="0" ItemsSource="{Binding RightItems}"
Direction="Column" SelectionMode="Single"
JustifyContent="Start" SelectionChanged="OnRightSelectionChanged"
AlignItems="Start" /> ItemSizingStrategy="MeasureAllItems">
</ScrollView> </CollectionView>
<!-- Toolbar --> <!-- Toolbar -->
<FlexLayout Grid.Row="3" <FlexLayout Grid.Row="3"

@ -9,13 +9,18 @@ public partial class MainPage : ContentPage, INotifyPropertyChanged
{ {
private readonly IFileSystemService _fileService; private readonly IFileSystemService _fileService;
// Коллекции больше не нужны для привязки, но оставим для логики
public ObservableCollection<FileSystemItem> LeftItems { get; } = new(); public ObservableCollection<FileSystemItem> LeftItems { get; } = new();
public ObservableCollection<FileSystemItem> RightItems { get; } = new(); public ObservableCollection<FileSystemItem> RightItems { get; } = new();
private string _leftPath = string.Empty; private string _leftPath = string.Empty;
private string _rightPath = 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 public string LeftPath
{ {
get => _leftPath; get => _leftPath;
@ -48,111 +53,195 @@ public partial class MainPage : ContentPage, INotifyPropertyChanged
private FileSystemItem? _selectedLeftItem; private FileSystemItem? _selectedLeftItem;
private FileSystemItem? _selectedRightItem; private FileSystemItem? _selectedRightItem;
// Для двойного нажатия
private FileSystemItem? _lastClickedItem;
private bool? _lastIsLeftPanel;
public MainPage(IFileSystemService fileService) public MainPage(IFileSystemService fileService)
{ {
InitializeComponent(); InitializeComponent();
_fileService = fileService; _fileService = fileService;
BindingContext = this; BindingContext = this;
// Инициализация шаблонов
InitializeCollectionViews();
var root = _fileService.GetRootPath(); var root = _fileService.GetRootPath();
LoadDirectory(root, true); LoadDirectory(root, true);
LoadDirectory(root, false); LoadDirectory(root, false);
// Устанавливаем фокус на страницу
this.Focus();
} }
private void LoadDirectory(string path, bool isLeft) private void InitializeCollectionViews()
{ {
var items = _fileService.GetDirectoryContents(path).ToList(); LeftPanel.ItemTemplate = PanelCollectionView.CreateItemTemplate(isLeftPanel: true, page: this);
var panel = isLeft ? LeftPanel : RightPanel; RightPanel.ItemTemplate = PanelCollectionView.CreateItemTemplate(isLeftPanel: true, page: this);
var targetItems = isLeft ? LeftItems : RightItems; }
var currentPathProperty = isLeft ? nameof(_currentLeftPath) : nameof(_currentRightPath);
// Очистка панели
panel.Clear();
targetItems.Clear();
// Заполнение protected override void OnHandlerChanged()
foreach (var item in items) {
{ base.OnHandlerChanged();
targetItems.Add(item); 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, _isLeftPanelActive = true;
TextColor = Colors.Black, _leftSelectedIndex = LeftItems.IndexOf(item);
Padding = new Thickness(10), _selectedLeftItem = item;
HeightRequest = 40, _selectedRightItem = null;
BackgroundColor = Colors.Transparent, }
BorderWidth = 0, else
CommandParameter = item {
}; _isLeftPanelActive = false;
_rightSelectedIndex = RightItems.IndexOf(item);
button.Clicked += isLeft ? OnLeftItemActivated : OnRightItemActivated; _selectedRightItem = item;
_selectedLeftItem = null;
// Добавляем визуальные состояния }
var normal = new VisualState { Name = "Normal" }; UpdateVisualSelection();
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);
} }
_lastIsLeftPanel = isLeftPanel;
_lastClickedItem = item;
}
private void LoadDirectory(string path, bool isLeft)
{
var items = _fileService.GetDirectoryContents(path).ToList();
// Обновление пути
if (isLeft) if (isLeft)
{ {
LeftItems.Clear();
foreach (var item in items) LeftItems.Add(item);
_currentLeftPath = path; _currentLeftPath = path;
LeftPath = path; LeftPath = path;
// Сбрасываем выделение при загрузке новой директории
_leftSelectedIndex = items.Count > 0 ? 0 : -1;
} }
else else
{ {
RightItems.Clear();
foreach (var item in items) RightItems.Add(item);
_currentRightPath = path; _currentRightPath = path;
RightPath = 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; // Обновляем индексы при программном изменении selection
var item = (FileSystemItem)button.CommandParameter; if (e.CurrentSelection.FirstOrDefault() is FileSystemItem selectedItem)
{
_leftSelectedIndex = LeftItems.IndexOf(selectedItem);
_isLeftPanelActive = true;
UpdateVisualSelection();
}
}
_selectedLeftItem = item; private void OnRightSelectionChanged(object sender, SelectionChangedEventArgs e)
_selectedRightItem = null; {
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; _selectedLeftItem = null;
} }
} }
private void OnRightItemActivated(object sender, EventArgs e) private void SetFocusToItem(CollectionView collectionView, FileSystemItem item)
{ {
var button = (Button)sender; // Используем Dispatcher чтобы дождаться рендеринга
var item = (FileSystemItem)button.CommandParameter; 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) if (item.IsDirectory)
{ {
LoadDirectory(item.FullName, false); LoadDirectory(item.FullName, false);
_selectedRightItem = null;
} }
} }
// Остальные методы без изменений
private async void OnCopyClicked(object sender, EventArgs e) private async void OnCopyClicked(object sender, EventArgs e)
{ {
await ProcessFileOperation(async (src, destDir) => await ProcessFileOperation(async (src, destDir) =>

@ -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;
});
}
}
Loading…
Cancel
Save