当前位置:网站首页>[winui3] Écrivez une copie du gestionnaire de fichiers Explorer
[winui3] Écrivez une copie du gestionnaire de fichiers Explorer
2022-04-23 04:50:00 【Lin Xiao.】
J'ai utiliséVueJ'ai écrit une imitationExplorerGestionnaire de fichiers,Voir l'articleAvecVueÉcrivez une simple imitationExplorerGestionnaire de fichiers_Lin Petit blog-CSDNBlogs_vueSystème de gestion des documents
Cette fois.MicrosoftWindows UI Bibliothèque (WinUI) 3 Pour reconstruire une version de bureauExplorerGestionnaire de fichiers.
Un.、Principes de navigation
Utilisez d'abord la barre de navigation et regardez attentivement,Nous avons plusieurs façons d'opérer:
- Cliquez sur“Vers le Haut”Bouton retour à la table des matières précédente,Cliquez sur le nom du dossier dans la barre d'adresse pour retourner à n'importe quel répertoire
- Double - cliquez sur le dossier pour entrer dans le nouveau répertoire
- Cliquez sur“En avant!”,“Reculez!”Navigation par bouton - poussoir
Où aller de l'avant,Marche arrière,Vous pouvez cliquer sur le petit triangle pour voir une liste,Cliquez pour entrer dans le dossier,La liste enregistre l'historique de navigation,Même entrer dans le même dossier à plusieurs reprises,La liste est toujours enregistrée,Comme le montre la figure ci - dessous::

Donc nous pouvons analyser et résumer deux variables:
- Une variable pour stocker la navigation réelle(navigationStack)
- Une autre variable utilisée pour stocker l'historique de navigation(navigationHistoryStack)
La pile de navigation est utilisée pour stocker des informations pour chaque dossier de navigation,Assemblez ces dossiers pour former le chemin actuel, Un ensemble simple de<li>Les éléments naviguent sur la pile en liant,Pour former une barre d'adresses(webDans le monde aussi appelé la navigation des miettes de pain)C'est.
navigationStackEn fait, c'est une pile,C'est une sortie avancée(FILO)Principes
L'historique de navigation n'enregistre que la trajectoire de l'utilisateur,Pas d'impact sur les cibles de navigation,Comme je viens de le dire,Même entrer dans le même dossier à plusieurs reprises,La liste est toujours enregistrée
navigationHistoryStackEn fait, c'est une file d'attente,Avec le premier entré, premier sorti(FIFO)Principes
Ensuite, on commence le Code
On va en construire un nouveauWinUI3Projets,NomméExplorerNavigation

Créer un nouveauObservableCollection<T>Type dérivé deObservableCollectionEx<T>,Et ensuite réaliser:
- push() La méthode peut ajouter un ou plusieurs éléments à la fin d'un tableau
- shift() Méthode pour supprimer le premier élément du tableau
- unshift() La méthode peut ajouter un ou plusieurs éléments à l'avant du tableau
- pop() Méthode pour supprimer le dernier élément du tableau
EtForEach()Traversée,EtIndexOf() Méthodes communes telles que l'interrogation des marques d'angle :
public class ObservableCollectionEx<T> : ObservableCollection<T>
{
public ObservableCollectionEx() : base()
{
}
public ObservableCollectionEx(IEnumerable<T> collection) : base(collection)
{
}
public ObservableCollectionEx(List<T> list) : base(list)
{
}
public void ForEach(Action<T> action)
{
for (int index = 0; index < this.Count; ++index)
action(this[index]);
}
public int IndexOf(Predicate<T> match)
{
var startIndex = 0;
for (int index = startIndex; index < this.Count; ++index)
{
if (match(this[index]))
{
return index;
}
}
return -1;
}
public void Shift()
{
if (this.Count == 0)
{
return;
}
this.Remove(this.First());
}
public void Unshift(T item)
{
this.Insert(0, item);
}
public void Pop()
{
if (this.Count == 0)
{
return;
}
this.Remove(this.Last());
}
public void Push(T item)
{
this.Add(item);
}
NouveauExplorerViewModelType, Il sera utilisé comme Explorer Base de la page de navigation ViewModel
ÉtablissementNavigationStack、NavigationHistoryStack Objet et initialisation dans le constructeur :
public ExplorerViewModel()
{
NavigationStack = new ObservableCollectionEx<IExplorerItem>();
NavigationHistoryStack = new ObservableCollectionEx<IExplorerItem>();
}
private ObservableCollectionEx<IExplorerItem> _navigationStack;
public ObservableCollectionEx<IExplorerItem> NavigationStack
{
get { return _navigationStack; }
set
{
_navigationStack = value;
OnPropertyChanged(nameof(NavigationStack));
}
}
private ObservableCollectionEx<IExplorerItem> _navigationHistoryStack;
public ObservableCollectionEx<IExplorerItem> NavigationHistoryStack
{
get { return _navigationHistoryStack; }
set
{
_navigationHistoryStack = value;
OnPropertyChanged(nameof(NavigationHistoryStack));
}
}
2.、Principe du saut de dossier
Commençons par la structure de données suivante
public interface IExplorerItem
{
ObservableCollection<IExplorerItem> Children { get; set; }
bool IsCurrent { get; set; }
bool IsExpanded { get; set; }
string Name { get; set; }
string Path { get; set; }
List<string> PathStack { get; }
ExplorerItemType Type { get; set; }
}
IExplorerItem Est une classe de description d'arbre définie ,Supposons qu'on ait un tas d'arbres de fichiers qui poussent comme ça:

L'objet arborescent correspondant est :
IExplorerItem root = new ExplorerItem()
{
Children = new ObservableCollection<IExplorerItem>() {
new ExplorerItem() {
Children = new ObservableCollection<IExplorerItem>() {
new ExplorerItem() {
Name = "DossiersB",
Path = "Mon disque réseau/DossiersA/DossiersB",
Type = ExplorerItemType.Folder
},
new ExplorerItem() {
Children = new ObservableCollection<IExplorerItem>() {
new ExplorerItem() {
Name = "DossiersD",
Path = "Mon disque réseau/DossiersA/DossiersC/DossiersD",
Type = ExplorerItemType.Folder
},
},
Name = "DossiersC",
Path = "Mon disque réseau/DossiersA/DossiersC",
Type = ExplorerItemType.Folder
},
new ExplorerItem() {
Name = "Documentation3",
Path = "Mon disque réseau/DossiersA/Documentation3",
Type = ExplorerItemType.File
}
},
Name = "DossiersA",
Path = "Mon disque réseau/DossiersA",
Type = ExplorerItemType.Folder
},
new ExplorerItem() {
Name = "Documentation1",
Path = "Mon disque réseau/Documentation1",
Type = ExplorerItemType.File
},
new ExplorerItem() {
Name = "Documentation2",
Path = "Mon disque réseau/Documentation2",
Type = ExplorerItemType.File
}
},
Name = "Mon disque réseau",
Path = "Mon disque réseau",
Type = ExplorerItemType.Folder
};
Trois、 Écrire une interface arborescente :
App.cs Définir l'injection dépendante dans
public App()
{
this.InitializeComponent();
InitializeComponent();
// Register services
if (!_initialized)
{
_initialized = true;
Ioc.Default.ConfigureServices(
new ServiceCollection()
//ViewModels
.AddSingleton<MainPageViewModel>()
.BuildServiceProvider());
}
}
NouveauMainPageViewModel.cs
InMainWindow.xaml.cs Lier l'objet contextuel de la page à MainPageViewModel
public MainWindow()
{
this.InitializeComponent();
this.MainFrame.DataContext = Ioc.Default.GetRequiredService<MainPageViewModel>();
}
InMainWindow.xaml Écrire un contrôle arborescent
<TreeView
ItemsSource="{Binding RootExplorerItems}" SelectedItem="{Binding CurrentExplorerItem ,Mode=TwoWay}"
ItemInvoked="TreeView_ItemInvoked"
SelectionMode="Single"
Margin="0,12"
>
<TreeView.ItemTemplate>
<DataTemplate
x:DataType="model:ExplorerItem">
<TreeViewItem AutomationProperties.Name="{Binding Name}"
ItemsSource="{Binding Children}" IsExpanded="True" >
<StackPanel Orientation="Horizontal">
<Image Width="20" Source="/Assets/folder.png" Visibility="{Binding Type, Converter={StaticResource isValueToVisibilityConverter}, ConverterParameter=Folder}"/>
<Image Width="20" Source="/Assets/file.png" Visibility="{Binding Type, Converter={StaticResource isValueToVisibilityConverter}, ConverterParameter=File}"/>
<TextBlock Margin="0,0,10,0"/>
<TextBlock Style="{StaticResource NavigationTextBlockStyle}"
Text="{Binding Name}" />
</StackPanel>
</TreeViewItem>
</DataTemplate>
</TreeView.ItemTemplate>
</TreeView>
Interface de rendu

Quatre、Écrivez la logique de navigation
Méthode de traitement de la pile de navigation :NavigationTo(IExplorerItem folder)
On vient d'analyser le principe de navigation,Le rôle de la pile de navigation est de former l'adresse,Nous définissons une logique de traitement de la pile de navigation:
- Déterminer si la page courante est dans la pile de navigation
- Si,Apparaît à l'emplacement de la cible dans la pile de navigation
- Si non,Appuyez sur la pile de navigation
Parmi euxToFolder Méthode utilisée pour naviguer et rafraîchir la page ,Plus tard
public virtual void NavigationTo(IExplorerItem folder)
{
DealWithNavigationStack(folder);
if (ToFolder(folder))
{
NavigationHistoryStack.ForEach((element) =>
{
element.IsCurrent = false;
});
folder.IsCurrent = true;
PushNavigationHistoryStack(folder);
}
}
“Vers le Haut”Méthodes de navigation:NavigationBack()
L'action vers le Haut appartient à un traitement spécifique de la pile de navigation:
- L'entrée la plus haute apparaît directement,
- Obtenez l'entrée supérieure et naviguez
private void NavigationBack()
{
if (NavigationStack.Count == 1)
{
return;
}
NavigationStack.Pop();
var lastItem = NavigationStack.LastOrDefault();
if (lastItem == null)
{
return;
}
if (ToFolder(lastItem))
{
NavigationHistoryStack.ForEach((element) =>
{
element.IsCurrent = false;
});
lastItem.IsCurrent = true;
PushNavigationHistoryStack(lastItem);
}
}
Méthode de saut: ToFolder,
De nombreuses méthodes ultérieures se réfèrent à cette méthode ,Cette fonction effectue simplement un saut,Objet de description du fichier entrant,Effectuer la navigation,Rafraîchir la page,RetourboolLa valeur représente le succès ou non:
public virtual bool ToFolder(IExplorerItem item)
{
if (item == null || item.Path == CurrentExplorerItem.Path)
{
return false;
}
var currentExplorerItem = NavigationStack.FirstOrDefault(c => c.Path == item.Path);
if (currentExplorerItem == null)
{
return false;
}
CurrentExplorerItem = currentExplorerItem;
return true;
}
Cinq、Écrire une logique de traitement de navigation historique
“Reculez!”Méthodes: NavigationHistoryBack()
- Déterminez d'abord où se trouve la page courante dans la navigation historique
- Après avoir reçu l'étiquette d'angle+1(Parce que c'est la file d'attente,Donc plus tôt l'angle est grand),Obtenez la dernière entrée de page dans la file d'attente de navigation historique, Et exécuter la méthode de navigation
private void NavigationHistoryBack()
{
var currentIndex = NavigationHistoryStack.IndexOf(
(c) => c.IsCurrent
);
if (currentIndex < NavigationHistoryStack.Count - 1)
{
var forwardIndex = currentIndex + 1;
var folder = NavigationHistoryStack[forwardIndex];
DealWithNavigationStack(folder);
if (ToFolder(folder))
{
NavigationHistoryStack.ForEach((element) =>
{
element.IsCurrent = false;
});
NavigationHistoryStack[forwardIndex].IsCurrent = true;
}
}
}
“En avant!”Méthodes:NavigationHistoryForward()
- Déterminez d'abord où se trouve la page courante dans la navigation historique
- Après avoir reçu l'étiquette d'angle-1(Parce que c'est la file d'attente,Donc plus tard, plus petit sera le coin.),Obtenez l'entrée de page précédente dans la file d'attente de navigation historique, Et exécuter la méthode de navigation
private void NavigationHistoryForward()
{
var currentIndex = NavigationHistoryStack.IndexOf(
(c) => c.IsCurrent
);
if (currentIndex > 0)
{
var forwardIndex = currentIndex - 1;
var folder = NavigationHistoryStack[forwardIndex];
DealWithNavigationStack(folder);
if (ToFolder(folder))
{
NavigationHistoryStack.ForEach((element) =>
{
element.IsCurrent = false;
});
NavigationHistoryStack[forwardIndex].IsCurrent = true;
}
}
}
Et nous avons besoin d'un moyen ,Utilisé pour afficher dans la file d'attente historique(En cours)Étiquettes:
public virtual bool GetIsCurrentHistoryNavigationItem(IExplorerItem item)
{
var result = item.IsCurrent;
return result;
}
Six、 Écrire l'interface de la barre de navigation :
InMainPageViewModel.cs Trois sont définis dans Command Liaison des boutons pour le Front End
public RelayCommand NavigationHistoryBackCommand { get; private set; }
public RelayCommand NavigationHistoryForwardCommand { get; private set; }
public RelayCommand NavigationBackCommand { get; private set; }
public ExplorerViewModel()
{
NavigationHistoryBackCommand = new RelayCommand(NavigationHistoryBack);
NavigationHistoryForwardCommand = new RelayCommand(NavigationHistoryForward);
NavigationBackCommand = new RelayCommand(NavigationBack);
}
In MainWindow.xamlMoyenne Compilation3Les boutons“En avant!”,“Reculez!”,“Vers le Haut”, Et lié au CommandAllez.
<StackPanel Orientation="Horizontal" >
<Button Style="{StaticResource NavigationBarButtonStyle}" Command="{Binding NavigationHistoryBackCommand}" Margin="10">
<FontIcon Style="{StaticResource NavigationBarButtonTextStyle}" Glyph=""/>
</Button>
<Button Style="{StaticResource NavigationBarButtonStyle}" Command="{Binding NavigationHistoryForwardCommand}" Margin="10" >
<FontIcon Style="{StaticResource NavigationBarButtonTextStyle}" Glyph=""/>
</Button>
<Button Style="{StaticResource NavigationBarButtonStyle}" Command="{Binding NavigationBackCommand}" Margin="10" >
<FontIcon Style="{StaticResource NavigationBarButtonTextStyle}" Glyph=""/>
</Button>
</StackPanel>
InMainPageViewModel.csDéfinition moyennePathStack
private ObservableCollection<string> _pathStack;
public ObservableCollection<string> PathStack
{
get { return _pathStack; }
set
{
_pathStack = value;
OnPropertyChanged(nameof(PathStack));
}
}
In MainWindow.xamlÉcrivez unBreadcrumbBar Comme zone d'entrée de la barre de navigation
<BreadcrumbBar VerticalAlignment="Center" HorizontalAlignment="Stretch" ItemsSource="{Binding PathStack}">
</BreadcrumbBar>
Interface de rendu:

InMainPageViewModel.csDéfinition moyenneCurrentFileInfos Comme liste de fichiers sous le chemin courant ,DéfinitionSelectedFileInfo Comme fichier actuellement sélectionné .
private ObservableCollectionEx<IFileInfo> _currentFileInfos;
public ObservableCollectionEx<IFileInfo> CurrentFileInfos
{
get { return _currentFileInfos; }
set
{
_currentFileInfos = value;
OnPropertyChanged(nameof(CurrentFileInfos));
}
}
private IFileInfo _selectedFileInfo;
public IFileInfo SelectedFileInfo
{
get { return _selectedFileInfo; }
set
{
_selectedFileInfo = value;
OnPropertyChanged(nameof(SelectedFileInfo));
}
}
In MainWindow.xamlÉcrit enGridView Présentation du contenu du catalogue
<!--File Content-->
<GridView
x:Name="BasicGridView"
IsItemClickEnabled="True"
ItemsSource="{Binding CurrentFileInfos}"
SelectedItem="{Binding SelectedFileInfo}"
ItemClick="BasicGridView_ItemClick"
SelectionMode="Single">
<GridView.ItemContainerStyle>
<Style TargetType="GridViewItem">
<Setter Property="Margin" Value="5, 7, 5, 7"/>
</Style>
</GridView.ItemContainerStyle>
<GridView.ItemTemplate>
<DataTemplate>
<Grid Width="100" Height="120" DoubleTapped="Grid_DoubleTapped">
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Image Grid.Row="0" Visibility="{Binding Type, Converter={StaticResource isValueToVisibilityConverter}, ConverterParameter=1}" Width="90" Source="/Assets/folder.png"/>
<Image Grid.Row="0" Visibility="{Binding Type, Converter={StaticResource isValueToVisibilityConverter}, ConverterParameter=2}" Width="90" Source="/Assets/file.png"/>
<TextBlock HorizontalAlignment="Center" Grid.Row="1" Text="{Binding FileName, Converter={StaticResource absoluteNameConverter}}" Style="{ThemeResource CaptionTextBlockStyle}"></TextBlock>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
Lorsque vous double - cliquez sur un élément dans la zone de fichier , Besoin d'ouvrir le fichier , Ou sauter dans le répertoire
InMainWindow.xaml.cs Pour écrire une liaison d'événement en double - clic
private async void Grid_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
{
var targetFile = (e.OriginalSource as FrameworkElement).DataContext as IFileInfo;
if (targetFile == null)
{
return;
}
if (targetFile.Type == FileInfoType.Folder)
{
var targetFolder = (this.MainFrame.DataContext as MainPageViewModel).CurrentExplorerItem.Children.FirstOrDefault(c => c.Name == targetFile.FileName);
if (targetFolder != null)
{
(this.MainFrame.DataContext as MainPageViewModel).NavigationTo(targetFolder);
}
}
else
{
ContentDialog subscribeDialog = new ContentDialog
{
Title = $" Vous avez ouvert le fichier [{targetFile.FileName}]",
CloseButtonText = "C'est sûr.",
DefaultButton = ContentDialogButton.Primary
};
subscribeDialog.XamlRoot = App.Window.Content.XamlRoot;
ContentDialogResult result = await subscribeDialog.ShowAsync();
}
}
Interface de rendu:
Effet final:

Entrepôt de code:
jevonsflash/ExplorerNavigation (github.com)
Conclusion:
C'est une simple navigation de fichier Demo, Vous pouvez créer des explorateurs de fichiers non locaux ,Pour remplacerWindows énorme et gonflé explorer.exe, Vous pouvez également créer un client de disque réseau ,ftp Outils et autres outils de gestion de fichiers en ligne .WinUI3 Est le dernier cadre de développement Microsoft Desktop , Le Code de ce projet peut également être facilement réécrit WpfOuUWPApplication.
Seven Niu Cloud upload Tool :
版权声明
本文为[Lin Xiao.]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/04/202204230449458663.html
边栏推荐
- 数据孤岛是什么?为什么2022年仍然存在数据孤岛?
- Sword finger offer: the path with a certain value in the binary tree (backtracking)
- io. Platform. packageRoot; // ignore: deprecated_ Member_ use
- MySQL queries users logged in for at least N consecutive days
- Unity rawimage background seamlessly connected mobile
- Perfect test of coil in wireless charging system with LCR meter
- Windows remote connection to redis
- Eight misunderstandings that should be avoided in data visualization
- Open the past and let's start over.
- KVM error: Failed to connect socket to ‘/var/run/libvirt/libvirt-sock‘
猜你喜欢
![解决ValueError: Argument must be a dense tensor: 0 - got shape [198602], but wanted [198602, 16].](/img/99/095063b72390adea6250f7b760d78c.png)
解决ValueError: Argument must be a dense tensor: 0 - got shape [198602], but wanted [198602, 16].

Mysql50 basic exercises

【数据库】MySQL单表查询

Wine (COM) - basic concept

Improving 3D object detection with channel wise transformer

简单的拖拽物体到物品栏

redis数据类型有哪些

Spell it! Two A-level universities and six B-level universities have abolished master's degree programs in software engineering!

Installation and deployment of Flink and wordcount test

Detailed explanation of the differences between TCP and UDP
随机推荐
selenium模式下切换窗口,抓取数据的实现
leetcode004--罗马数字转整数
Pixel mobile phone brick rescue tutorial
Eight misunderstandings that should be avoided in data visualization
Programmers complain: I really can't live with a salary of 12000. Netizen: how can I say 3000
简单的拖拽物体到物品栏
Gets all dates between two times
Introduction to raspberry pie 3B - system installation
redis数据类型有哪些
Solve valueerror: argument must be a deny tensor: 0 - got shape [198602], but wanted [198602, 16]
Innovation training (XI) airline ticket crawling company information
Unity camera rotation with sliding effect (rotation)
View analysis of scenic spots in ArcGIS
getprop 属性
[paper reading] [3D object detection] voxel transformer for 3D object detection
Excel protects worksheets and workbooks from damage
Raspberry pie + opencv + opencv -- face detection ------- environment construction
The 14th issue of HMS core discovery reviews the long article | enjoy the silky clip and release the creativity of the video
【数据库】MySQL单表查询
Arduino UNO r3+LCD1602+DHT11
