collection

main
Stepan Pilipenko 4 weeks ago
parent e4511340a9
commit de6eae9d06

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

@ -9,13 +9,18 @@ public partial class MainPage : ContentPage, INotifyPropertyChanged
{
private readonly IFileSystemService _fileService;
// Коллекции больше не нужны для привязки, но оставим для логики
public ObservableCollection<FileSystemItem> LeftItems { get; } = new();
public ObservableCollection<FileSystemItem> 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) =>

@ -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