init FileBrowser
This commit is contained in:
88
.gitignore
vendored
Normal file
88
.gitignore
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
# Build results
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
*.user
|
||||
*.suo
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# .NET Core build results
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# Windows image file caches
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
|
||||
# Visual Studio for Mac
|
||||
.vscode/
|
||||
.idea/
|
||||
*.userprefs
|
||||
|
||||
# Rider
|
||||
*.sln.iml
|
||||
|
||||
# Web/ASP.NET (not needed for WPF, but often included)
|
||||
*.publish.xml
|
||||
*.azurePubxml
|
||||
*.azurePubxml.user
|
||||
PublishProfiles/
|
||||
|
||||
# NuGet
|
||||
*.nupkg
|
||||
*.snupkg
|
||||
.nuget/
|
||||
packages/
|
||||
*.nuspec
|
||||
project.assets.json
|
||||
PackageRestoreEnabled.txt
|
||||
|
||||
# MSTest test results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# Visual Studio Code settings
|
||||
.vscode/
|
||||
|
||||
# Backup & temp files
|
||||
*.bak
|
||||
*.tmp
|
||||
*.temp
|
||||
*.log
|
||||
|
||||
# Resharper
|
||||
_ReSharper*/
|
||||
*.DotSettings.user
|
||||
|
||||
# Rider
|
||||
.idea/
|
||||
|
||||
# WPF specific (if generated)
|
||||
Generated_Code/
|
||||
|
||||
# Local config files
|
||||
appsettings.Development.json
|
||||
app.config
|
||||
web.config
|
||||
|
||||
# Crash reports
|
||||
*.dmp
|
||||
|
||||
# Others
|
||||
*.dbmdl
|
||||
*.jfm
|
||||
*.sdf
|
||||
*.cache
|
||||
*.pdb
|
||||
*.mdb
|
||||
|
||||
# Ignore git itself
|
||||
.git/
|
||||
|
||||
|
||||
.vs/
|
||||
25
FileBrowser.sln
Normal file
25
FileBrowser.sln
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.11.35208.52
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileBrowser", "FileBrowser\FileBrowser.csproj", "{13CB098D-6CE7-4FC9-8E05-B5D9D3977B88}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{13CB098D-6CE7-4FC9-8E05-B5D9D3977B88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{13CB098D-6CE7-4FC9-8E05-B5D9D3977B88}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{13CB098D-6CE7-4FC9-8E05-B5D9D3977B88}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{13CB098D-6CE7-4FC9-8E05-B5D9D3977B88}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {567C0FE1-762F-4A8A-8F95-CEE68A3BDCF5}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
9
FileBrowser/App.xaml
Normal file
9
FileBrowser/App.xaml
Normal file
@@ -0,0 +1,9 @@
|
||||
<Application x:Class="FileBrowser.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:FileBrowser"
|
||||
Startup="OnStartup">
|
||||
<Application.Resources>
|
||||
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
30
FileBrowser/App.xaml.cs
Normal file
30
FileBrowser/App.xaml.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using FileBrowser.Services;
|
||||
using FileBrowser.ViewModels;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using System.Windows;
|
||||
|
||||
namespace FileBrowser;
|
||||
|
||||
/// <summary>
|
||||
/// Interaction logic for App.xaml
|
||||
/// </summary>
|
||||
public partial class App : Application
|
||||
{
|
||||
private IServiceProvider _provider;
|
||||
|
||||
private void OnStartup(object sender, StartupEventArgs e)
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
|
||||
services.AddSingleton<IFileService, FileService>();
|
||||
services.AddSingleton<MainViewModel>();
|
||||
services.AddTransient<MainWindow>(); // window created with DI
|
||||
|
||||
_provider = services.BuildServiceProvider();
|
||||
|
||||
var wnd = _provider.GetRequiredService<MainWindow>();
|
||||
// Set DataContext with DI-provided VM (no code-behind in view)
|
||||
wnd.DataContext = _provider.GetRequiredService<MainViewModel>();
|
||||
wnd.Show();
|
||||
}
|
||||
}
|
||||
10
FileBrowser/AssemblyInfo.cs
Normal file
10
FileBrowser/AssemblyInfo.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System.Windows;
|
||||
|
||||
[assembly: ThemeInfo(
|
||||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||
//(used if a resource is not found in the page,
|
||||
// or application resource dictionaries)
|
||||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||
//(used if a resource is not found in the page,
|
||||
// app, or any theme specific resource dictionaries)
|
||||
)]
|
||||
15
FileBrowser/FileBrowser.csproj
Normal file
15
FileBrowser/FileBrowser.csproj
Normal file
@@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<UseWPF>true</UseWPF>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.8" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
21
FileBrowser/Helpers/RelayCommand.cs
Normal file
21
FileBrowser/Helpers/RelayCommand.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace FileBrowser.Helpers;
|
||||
|
||||
public class RelayCommand : ICommand
|
||||
{
|
||||
private readonly Action<object?> _execute;
|
||||
private readonly Func<object?, bool>? _canExecute;
|
||||
|
||||
public RelayCommand(Action<object?> execute, Func<object?, bool>? canExecute = null)
|
||||
{
|
||||
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
|
||||
_canExecute = canExecute;
|
||||
}
|
||||
|
||||
public bool CanExecute(object? parameter) => _canExecute?.Invoke(parameter) ?? true;
|
||||
public void Execute(object? parameter) => _execute(parameter);
|
||||
|
||||
public event EventHandler? CanExecuteChanged;
|
||||
public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
73
FileBrowser/MainWindow.xaml
Normal file
73
FileBrowser/MainWindow.xaml
Normal file
@@ -0,0 +1,73 @@
|
||||
<Window x:Class="FileBrowser.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:FileBrowser"
|
||||
mc:Ignorable="d"
|
||||
Title="Keyboard File Browser" Height="600" Width="1000">
|
||||
<Window.InputBindings>
|
||||
<!-- Tab: Enter / Open -->
|
||||
<KeyBinding Key="Tab" Command="{Binding EnterCommand}" />
|
||||
<!-- Shift+Tab: Up one folder -->
|
||||
<KeyBinding Key="Tab" Modifiers="Shift" Command="{Binding UpCommand}" />
|
||||
<!-- F5 refresh -->
|
||||
<KeyBinding Key="F5" Command="{Binding RefreshCommand}" />
|
||||
</Window.InputBindings>
|
||||
|
||||
<DockPanel LastChildFill="True" Margin="6">
|
||||
<!-- Top: Path -->
|
||||
<TextBlock DockPanel.Dock="Top" Text="{Binding CurrentPath}" d:Text="c:/Test" FontWeight="Bold"
|
||||
Padding="4" />
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="2*" />
|
||||
<ColumnDefinition Width="4*" />
|
||||
<ColumnDefinition Width="3*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Left: Parent folder contents -->
|
||||
<Border Grid.Column="0" BorderBrush="Gray" BorderThickness="1" Margin="4"
|
||||
Padding="4">
|
||||
<StackPanel>
|
||||
<TextBlock Text="Parent / Siblings" FontWeight="SemiBold" />
|
||||
<ListBox ItemsSource="{Binding ParentItems}"
|
||||
SelectedItem="{Binding SelectedParentItem}"
|
||||
DisplayMemberPath="Name"
|
||||
KeyboardNavigation.TabNavigation="Local"
|
||||
Focusable="False" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Middle: Current folder contents and filter input (keyboard-only) -->
|
||||
<Border Grid.Column="1" BorderBrush="Gray" BorderThickness="1" Margin="4"
|
||||
Padding="4">
|
||||
<DockPanel>
|
||||
<TextBlock DockPanel.Dock="Top" Text="Current Folder (type to filter)" />
|
||||
<!-- Hidden TextBox takes all typing for filter -->
|
||||
<TextBox x:Name="FilterBox"
|
||||
Text="{Binding FilterText, UpdateSourceTrigger=PropertyChanged}"
|
||||
Height="0.0" Opacity="0" Focusable="True"/>
|
||||
<ListBox ItemsSource="{Binding CurrentView}"
|
||||
SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
|
||||
DisplayMemberPath="Name"
|
||||
IsSynchronizedWithCurrentItem="True"
|
||||
KeyboardNavigation.TabNavigation="Local" />
|
||||
</DockPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Right: Preview -->
|
||||
<Border Grid.Column="2" BorderBrush="Gray" BorderThickness="1" Margin="4"
|
||||
Padding="4">
|
||||
<StackPanel>
|
||||
<TextBlock Text="Preview" FontWeight="SemiBold" />
|
||||
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
|
||||
<!-- Einfacher Text-Preview -->
|
||||
<TextBlock Text="{Binding PreviewText}" TextWrapping="Wrap" />
|
||||
</ScrollViewer>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
</Window>
|
||||
14
FileBrowser/MainWindow.xaml.cs
Normal file
14
FileBrowser/MainWindow.xaml.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace FileBrowser;
|
||||
|
||||
/// <summary>
|
||||
/// Interaction logic for MainWindow.xaml
|
||||
/// </summary>
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
10
FileBrowser/Models/FileItem.cs
Normal file
10
FileBrowser/Models/FileItem.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System.IO;
|
||||
|
||||
namespace FileBrowser.Models;
|
||||
|
||||
public class FileItem
|
||||
{
|
||||
public string FullPath { get; set; }
|
||||
public string Name => Path.GetFileName(FullPath) ?? FullPath;
|
||||
public bool IsDirectory => Directory.Exists(FullPath);
|
||||
}
|
||||
51
FileBrowser/Services/FileService.cs
Normal file
51
FileBrowser/Services/FileService.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using FileBrowser.Models;
|
||||
using System.IO;
|
||||
|
||||
namespace FileBrowser.Services;
|
||||
|
||||
public class FileService : IFileService
|
||||
{
|
||||
public string GetParentDirectory(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
var di = Directory.GetParent(path);
|
||||
return di?.FullName ?? path;
|
||||
}
|
||||
catch { return path; }
|
||||
}
|
||||
|
||||
public IEnumerable<FileItem> GetDirectoryItems(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
var dirs = Directory.EnumerateDirectories(path)
|
||||
.Select(d => new FileItem { FullPath = d });
|
||||
var files = Directory.EnumerateFiles(path)
|
||||
.Select(f => new FileItem { FullPath = f });
|
||||
return dirs.Concat(files).OrderBy(i => i.IsDirectory ? 0 : 1).ThenBy(i => i.Name);
|
||||
}
|
||||
catch { return Array.Empty<FileItem>(); }
|
||||
}
|
||||
|
||||
public string? ReadTextPreview(string path, int maxChars = 20000)
|
||||
{
|
||||
try
|
||||
{
|
||||
var ext = Path.GetExtension(path)?.ToLowerInvariant();
|
||||
var textExts = new[] { ".txt", ".cs", ".config", ".json", ".xml", ".log", ".md", ".csv" };
|
||||
if (!textExts.Contains(ext)) return null;
|
||||
using var sr = new StreamReader(path);
|
||||
var s = sr.ReadToEnd();
|
||||
if (s.Length > maxChars) s = s.Substring(0, maxChars) + "\n... (truncated)";
|
||||
return s;
|
||||
}
|
||||
catch { return null; }
|
||||
}
|
||||
|
||||
public bool IsImage(string path)
|
||||
{
|
||||
var ext = Path.GetExtension(path)?.ToLowerInvariant();
|
||||
return ext == ".png" || ext == ".jpg" || ext == ".jpeg" || ext == ".bmp" || ext == ".gif";
|
||||
}
|
||||
}
|
||||
11
FileBrowser/Services/IFileService.cs
Normal file
11
FileBrowser/Services/IFileService.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using FileBrowser.Models;
|
||||
|
||||
namespace FileBrowser.Services;
|
||||
|
||||
public interface IFileService
|
||||
{
|
||||
string GetParentDirectory(string path);
|
||||
IEnumerable<FileItem> GetDirectoryItems(string path);
|
||||
string? ReadTextPreview(string path, int maxChars = 20000);
|
||||
bool IsImage(string path);
|
||||
}
|
||||
242
FileBrowser/ViewModels/MainViewModel.cs
Normal file
242
FileBrowser/ViewModels/MainViewModel.cs
Normal file
@@ -0,0 +1,242 @@
|
||||
using FileBrowser.Helpers;
|
||||
using FileBrowser.Models;
|
||||
using FileBrowser.Services;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace FileBrowser.ViewModels;
|
||||
|
||||
public class MainViewModel : INotifyPropertyChanged
|
||||
{
|
||||
private readonly IFileService _fileService;
|
||||
|
||||
public MainViewModel(IFileService fileService)
|
||||
{
|
||||
_fileService = fileService ?? throw new ArgumentNullException(nameof(fileService));
|
||||
|
||||
ParentItems = new ObservableCollection<FileItem>();
|
||||
CurrentItems = new ObservableCollection<FileItem>();
|
||||
|
||||
// Commands zuerst initialisieren
|
||||
EnterCommand = new RelayCommand(_ => EnterOrOpen(), _ => SelectedItem != null);
|
||||
UpCommand = new RelayCommand(_ => Up(), _ => CanGoUp());
|
||||
RefreshCommand = new RelayCommand(_ => Refresh());
|
||||
|
||||
// CollectionView danach erzeugen
|
||||
_currentView = CollectionViewSource.GetDefaultView(CurrentItems);
|
||||
if (_currentView != null)
|
||||
_currentView.Filter = FilterPredicate;
|
||||
|
||||
// Defaults
|
||||
CurrentPath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) ?? @"C:\";
|
||||
FilterText = string.Empty;
|
||||
|
||||
// Jetzt sicher Refresh aufrufen (SelectedItem kann gesetzt werden ohne Nullref)
|
||||
try { Refresh(); }
|
||||
catch (Exception ex) { Debug.WriteLine("Initial Refresh failed: " + ex); }
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
private void Raise(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
|
||||
|
||||
private string _currentPath = "";
|
||||
public string CurrentPath
|
||||
{
|
||||
get => _currentPath;
|
||||
set
|
||||
{
|
||||
if (_currentPath == value) return;
|
||||
_currentPath = value;
|
||||
Raise(nameof(CurrentPath));
|
||||
Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
public ObservableCollection<FileItem> ParentItems { get; } = new ObservableCollection<FileItem>();
|
||||
public ObservableCollection<FileItem> CurrentItems { get; } = new ObservableCollection<FileItem>();
|
||||
|
||||
private ICollectionView _currentView;
|
||||
public ICollectionView CurrentView => _currentView;
|
||||
|
||||
private FileItem? _selectedParentItem;
|
||||
public FileItem? SelectedParentItem
|
||||
{
|
||||
get => _selectedParentItem;
|
||||
set
|
||||
{
|
||||
_selectedParentItem = value;
|
||||
if (value != null)
|
||||
{
|
||||
// selecting a sibling sets CurrentPath to its parent (no auto-enter)
|
||||
}
|
||||
Raise(nameof(SelectedParentItem));
|
||||
}
|
||||
}
|
||||
|
||||
private FileItem? _selectedItem;
|
||||
public FileItem? SelectedItem
|
||||
{
|
||||
get => _selectedItem;
|
||||
set
|
||||
{
|
||||
_selectedItem = value;
|
||||
UpdatePreview();
|
||||
Raise(nameof(SelectedItem));
|
||||
// Sicherstellen, dass EnterCommand existiert und vom erwarteten Typ ist,
|
||||
// bevor RaiseCanExecuteChanged aufgerufen wird.
|
||||
if (EnterCommand is RelayCommand rc)
|
||||
{
|
||||
rc.RaiseCanExecuteChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string? _previewText;
|
||||
public string? PreviewText
|
||||
{
|
||||
get => _previewText;
|
||||
set { _previewText = value; Raise(nameof(PreviewText)); }
|
||||
}
|
||||
|
||||
private string _filterText = "";
|
||||
public string FilterText
|
||||
{
|
||||
get => _filterText;
|
||||
set
|
||||
{
|
||||
_filterText = value;
|
||||
_currentView.Refresh();
|
||||
Raise(nameof(FilterText));
|
||||
}
|
||||
}
|
||||
|
||||
private bool FilterPredicate(object obj)
|
||||
{
|
||||
if (obj is FileItem fi)
|
||||
{
|
||||
if (string.IsNullOrEmpty(FilterText)) return true;
|
||||
return fi.Name.IndexOf(FilterText, StringComparison.OrdinalIgnoreCase) >= 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void UpdatePreview()
|
||||
{
|
||||
PreviewText = null;
|
||||
if (SelectedItem == null) return;
|
||||
|
||||
// Schütze _fileService gegen Null
|
||||
if (_fileService == null) return;
|
||||
|
||||
if (SelectedItem.IsDirectory) return;
|
||||
|
||||
var txt = _fileService.ReadTextPreview(SelectedItem.FullPath);
|
||||
if (txt != null)
|
||||
{
|
||||
PreviewText = txt;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_fileService.IsImage(SelectedItem.FullPath))
|
||||
{
|
||||
PreviewText = SelectedItem.FullPath;
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand EnterCommand { get; }
|
||||
public ICommand UpCommand { get; }
|
||||
public ICommand RefreshCommand { get; }
|
||||
|
||||
private void Refresh()
|
||||
{
|
||||
// Defensive programming to avoid NullReferenceExceptions
|
||||
if (ParentItems == null || CurrentItems == null)
|
||||
throw new InvalidOperationException("Collections were not initialized.");
|
||||
|
||||
// clear existing
|
||||
ParentItems.Clear();
|
||||
CurrentItems.Clear();
|
||||
|
||||
// normalize CurrentPath
|
||||
var path = string.IsNullOrWhiteSpace(CurrentPath) ? Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) : CurrentPath;
|
||||
|
||||
// Determine parent folder for sibling listing; if none, use the same path
|
||||
string parentForSiblings;
|
||||
try
|
||||
{
|
||||
var parentDirInfo = Directory.GetParent(path);
|
||||
parentForSiblings = parentDirInfo?.FullName ?? path;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine("Directory.GetParent failed: " + ex);
|
||||
parentForSiblings = path;
|
||||
}
|
||||
|
||||
// Get items safely from service (service should itself be robust)
|
||||
IEnumerable<FileItem> parentItems;
|
||||
try { parentItems = _fileService.GetDirectoryItems(parentForSiblings) ?? Array.Empty<FileItem>(); }
|
||||
catch (Exception ex) { Debug.WriteLine("GetDirectoryItems(parent) failed: " + ex); parentItems = Array.Empty<FileItem>(); }
|
||||
|
||||
foreach (var item in parentItems) ParentItems.Add(item);
|
||||
|
||||
IEnumerable<FileItem> currentItems;
|
||||
try { currentItems = _fileService.GetDirectoryItems(path) ?? Array.Empty<FileItem>(); }
|
||||
catch (Exception ex) { Debug.WriteLine("GetDirectoryItems(current) failed: " + ex); currentItems = Array.Empty<FileItem>(); }
|
||||
|
||||
foreach (var item in currentItems) CurrentItems.Add(item);
|
||||
|
||||
// Refresh view safely
|
||||
try { _currentView?.Refresh(); }
|
||||
catch (Exception ex) { Debug.WriteLine("CollectionView.Refresh failed: " + ex); }
|
||||
|
||||
// Select first available safely
|
||||
SelectedItem = CurrentItems.FirstOrDefault();
|
||||
SelectedParentItem = ParentItems.FirstOrDefault(o => o.FullPath.Contains(CurrentPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)));
|
||||
|
||||
// Notify (collections changed notifications come from ObservableCollection,
|
||||
// but we raise to be safe)
|
||||
Raise(nameof(ParentItems));
|
||||
Raise(nameof(CurrentItems));
|
||||
Raise(nameof(CurrentView));
|
||||
}
|
||||
|
||||
private bool CanGoUp() => Directory.GetParent(CurrentPath) != null;
|
||||
|
||||
private void Up()
|
||||
{
|
||||
var parent = Directory.GetParent(CurrentPath)?.FullName;
|
||||
if (parent != null)
|
||||
{
|
||||
CurrentPath = parent;
|
||||
FilterText = "";
|
||||
}
|
||||
}
|
||||
|
||||
private void EnterOrOpen()
|
||||
{
|
||||
if (SelectedItem == null) return;
|
||||
if (SelectedItem.IsDirectory)
|
||||
{
|
||||
CurrentPath = SelectedItem.FullPath;
|
||||
FilterText = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
ProcessStartInfo psi = new ProcessStartInfo
|
||||
{
|
||||
FileName = SelectedItem.FullPath,
|
||||
UseShellExecute = true
|
||||
};
|
||||
Process.Start(psi);
|
||||
}
|
||||
catch { /* ignore failures */ }
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user