Skip to content

Commit

Permalink
优化图标加载方式,将工作分配到独立线程,减少UI卡顿;优化文件夹加载方式,当文件很多时,会采用惰性加载策略。
Browse files Browse the repository at this point in the history
  • Loading branch information
DearVa committed Aug 12, 2022
1 parent 827d6e9 commit 92d1713
Show file tree
Hide file tree
Showing 27 changed files with 821 additions and 205 deletions.
1 change: 1 addition & 0 deletions ExplorerEx/App.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
<c:Int2VisibilityConverter x:Key="Int2VisibilityConverter"/>
<c:Int2VisibilityReConverter x:Key="Int2VisibilityReConverter"/>
<c:FileName2IconConverter x:Key="FileName2IconConverter"/>
<c:FileDateTime2StringConverter x:Key="FileDateTime2StringConverter"/>
<c:FullPath2FileNameConverter x:Key="FullPath2FileNameConverter"/>
<c:Bytes2StringConverter x:Key="Bytes2StringConverter"/>
<u:LangConverter x:Key="LangConverter"/>
Expand Down
8 changes: 3 additions & 5 deletions ExplorerEx/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,10 @@
namespace ExplorerEx;

public partial class App {
public static App Instance { get; private set; } = null!;
public static Arguments Args { get; private set; } = null!;
public static int ProcessorCount { get; private set; }

private App() {
Instance = this;
}
private App() { }

private static bool isRunning;
private static Mutex? mutex;
Expand Down Expand Up @@ -66,8 +63,9 @@ public partial class App {
IsBackground = true
}.Start();

ProcessorCount = Environment.ProcessorCount;

Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
Shell32Interop.Initialize();
IconHelper.InitializeDefaultIcons(Resources);
Settings.Current.LoadSettings();
ChangeTheme(((SolidColorBrush)SystemParameters.WindowGlassBrush).Color, false);
Expand Down
9 changes: 2 additions & 7 deletions ExplorerEx/Command/FileItemCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ public class FileItemCommand : ICommand {
break;
}
case "Paste": {
if (Folder != null && Clipboard.GetDataObject() is DataObject data) {
if (Clipboard.GetDataObject() is DataObject data) {
if (data.GetData(DataFormats.FileDrop) is string[] filePaths) {
bool isCut;
if (data.GetData("IsCut") is bool i) {
Expand Down Expand Up @@ -136,9 +136,6 @@ public class FileItemCommand : ICommand {
break;
}
case "Delete": // 删除一个或多个文件,按住shift就是强制删除
if (Folder == null) {
return;
}
if ((Keyboard.Modifiers & ModifierKeys.Shift) != ModifierKeys.Shift) { // 没有按Shift
if (!MessageBoxHelper.AskWithDefault("Recycle", "#AreYouSureToRecycleTheseFiles".L())) {
return;
Expand Down Expand Up @@ -200,9 +197,7 @@ public class FileItemCommand : ICommand {
}
break;
case "Terminal":
if (Folder != null) {
Terminal.RunTerminal(Folder.FullPath);
}
Terminal.RunTerminal(Folder.FullPath);
break;
case "ShowMore": {
if (!ConfigHelper.LoadBoolean("ShowMore")) {
Expand Down
19 changes: 19 additions & 0 deletions ExplorerEx/Converter/FileDateTime2StringConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using System.Globalization;
using System.Windows.Data;

namespace ExplorerEx.Converter;

internal class FileDateTime2StringConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
var dt = (DateTime)value;
if (dt == DateTime.MaxValue) {
return string.Empty;
}
return dt.ToString(CultureInfo.CurrentUICulture);
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
throw new NotImplementedException();
}
}
6 changes: 3 additions & 3 deletions ExplorerEx/Model/FileItem/Bookmark.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public class BookmarkCategory : NotifyPropertyChangedBase {

public virtual ObservableCollection<BookmarkItem>? Children { get; set; }

public BookmarkCategory() { }
private BookmarkCategory() { }

public BookmarkCategory(string name) {
Name = name;
Expand Down Expand Up @@ -71,9 +71,9 @@ public class BookmarkItem : FileListViewItem, IFilterable {

public BookmarkCategory Category { get; set; } = null!;

public BookmarkItem() : base(null!, null!) { }
private BookmarkItem() : base(null!, null!, false) { }

public BookmarkItem(string fullPath, string name, BookmarkCategory category) : base(null!, null!) {
public BookmarkItem(string fullPath, string name, BookmarkCategory category) : base(null!, null!, false) {
FullPath = Path.GetFullPath(fullPath);
Name = name;
Category = category;
Expand Down
85 changes: 67 additions & 18 deletions ExplorerEx/Model/FileItem/FileListViewItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,23 @@
using ExplorerEx.Utils;
using ExplorerEx.View.Controls;

namespace ExplorerEx.Model;
namespace ExplorerEx.Model;

/// <summary>
/// 所有可以显示在<see cref="FileListView"/>中的项目的基类
/// </summary>
public abstract class FileListViewItem : INotifyPropertyChanged {
protected FileListViewItem(string fullPath, string name) {
protected FileListViewItem(string fullPath, string name, bool isFolder) {
FullPath = fullPath;
Name = name;
defaultIcon = isFolder ? IconHelper.FolderDrawingImage : IconHelper.UnknownFileDrawingImage;
This = this;
}

protected FileListViewItem(string fullPath, string name, ImageSource defaultIcon) {
FullPath = fullPath;
Name = name;
this.defaultIcon = defaultIcon;
This = this;
}

Expand All @@ -30,7 +38,13 @@ public abstract class FileListViewItem : INotifyPropertyChanged {
/// </summary>
[NotMapped]
public ImageSource? Icon {
get => icon;
get {
if (icon != null) {
return icon;
}
Task.Run(() => LoadIcon(LoadDetailsOptions.Default));
return defaultIcon;
}
protected set {
if (icon != value) {
icon = value;
Expand All @@ -41,8 +55,10 @@ public abstract class FileListViewItem : INotifyPropertyChanged {

private ImageSource? icon;

protected readonly ImageSource defaultIcon;

[Key]
public string FullPath { get; protected set; }
public string FullPath { get; protected init; }

public abstract string DisplayText { get; }

Expand Down Expand Up @@ -139,7 +155,19 @@ public abstract class FileListViewItem : INotifyPropertyChanged {
#endregion

public override string ToString() {
return DisplayText;
return FullPath;
}

public override int GetHashCode() {
return FullPath.GetHashCode();
}

public override bool Equals(object? other) {
return other is FileListViewItem i && i.FullPath == FullPath;
}

public bool Equals(FileListViewItem other) {
return other.FullPath == FullPath;
}

/// <summary>
Expand All @@ -149,32 +177,46 @@ public abstract class FileListViewItem : INotifyPropertyChanged {
/// <param name="token"></param>
/// <param name="options"></param>
/// <returns></returns>
public static async Task LoadDetails(IReadOnlyCollection<FileListViewItem> list, CancellationToken token, LoadDetailsOptions options) {
try {
if (list.Count > 0) {
await Task.WhenAll(Partitioner.Create(list).GetPartitions(4).Select(partition => Task.Run(() => {
public static async Task LoadDetails(IReadOnlyCollection<FileListViewItem>? list, LoadDetailsOptions options, CancellationToken token) {
if (list is { Count: > 0 }) {
try {
var tasks = Partitioner.Create(list).GetPartitions(Math.Max(App.ProcessorCount, 2)).Select(partition => Task.Run(() => {
if (token.IsCancellationRequested) {
return Task.FromCanceled(token);
}
using (partition) {
while (partition.MoveNext()) {
var item = partition.Current!;
item.LoadAttributes(options);
item.LoadIcon(options);
if (token.IsCancellationRequested) {
return Task.FromCanceled(token);
}
partition.Current.LoadAttributes(options);
}
}
return Task.CompletedTask;
}, token)));
}, token));

if (options.PreLoadIcon) {
tasks = tasks.Append(Task.Run(() => {
foreach (var item in list) {
if (token.IsCancellationRequested) {
return Task.FromCanceled(token);
}
item.LoadIcon(options);
}
return Task.CompletedTask;
}, token));
}

await Task.WhenAll(tasks);
} catch (TaskCanceledException) {
// Ignore
} catch (Exception e) {
Logger.Exception(e);
}
} catch (TaskCanceledException) {
// Ignore
} catch (Exception e) {
Logger.Exception(e);
}
}

Expand All @@ -184,10 +226,17 @@ public abstract class FileListViewItem : INotifyPropertyChanged {
/// </summary>
public class LoadDetailsOptions {
public static LoadDetailsOptions Default { get; } = new() {
PreLoadIcon = true,
UseLargeIcon = false
};

public bool PreLoadIcon { get; set; }

public bool UseLargeIcon { get; set; }

public void SetPreLoadIconByItemCount(int count) {
PreLoadIcon = count / App.ProcessorCount < 20;
}
}

/// <summary>
Expand Down
33 changes: 17 additions & 16 deletions ExplorerEx/Model/FileItem/FileSystemItem.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Windows.Media;
using ExplorerEx.Shell32;
using ExplorerEx.Utils;
using static ExplorerEx.Utils.IconHelper;
Expand All @@ -24,7 +26,7 @@ public abstract class FileSystemItem : FileListViewItem {
}
}

private DateTime dateModified;
private DateTime dateModified = DateTime.MaxValue;

/// <summary>
/// 自动更新UI
Expand All @@ -39,16 +41,13 @@ public abstract class FileSystemItem : FileListViewItem {
}
}

private DateTime dateCreated;
private DateTime dateCreated = DateTime.MaxValue;

public override string GetRenameName() {
return Name;
}

protected override bool InternalRename(string newName) {
if (newName == null) {
return false;
}
var basePath = Path.GetDirectoryName(FullPath);
if (Path.GetExtension(FullPath) != Path.GetExtension(newName)) {
if (!MessageBoxHelper.AskWithDefault("RenameExtension", "#AreYouSureToChangeExtension".L())) {
Expand All @@ -75,7 +74,9 @@ public abstract class FileSystemItem : FileListViewItem {
LoadAttributes(options);
}

protected FileSystemItem(string fullPath, string name) : base(fullPath, name) { }
protected FileSystemItem(string fullPath, string name, bool isFolder) : base(fullPath, name, isFolder) { }

protected FileSystemItem(string fullPath, string name, ImageSource defaultIcon) : base(fullPath, name, defaultIcon) { }
}

public class FileItem : FileSystemItem {
Expand All @@ -100,13 +101,12 @@ public class FileItem : FileSystemItem {

public override string DisplayText => Name;

protected FileItem() : base(null!, null!) { }
protected FileItem() : base(null!, null!, false) { }

public FileItem(FileInfo fileInfo) : base(fileInfo.FullName, fileInfo.Name) {
public FileItem(FileInfo fileInfo) : base(fileInfo.FullName, fileInfo.Name, false) {
FileInfo = fileInfo;
IsFolder = false;
FileSize = -1;
Icon = UnknownFileDrawingImage;
}

public override void LoadAttributes(LoadDetailsOptions options) {
Expand Down Expand Up @@ -186,25 +186,26 @@ public class FolderItem : FileSystemItem {

private bool isEmptyFolder;

protected FolderItem() : base(null!, null!) { }
protected FolderItem() : base(null!, null!, true) { }

public FolderItem(string fullPath): base(fullPath, Path.GetFileName(fullPath)) {
public FolderItem(string fullPath): base(fullPath, Path.GetFileName(fullPath), InitializeIsEmptyFolder(fullPath)) {
IsFolder = true;
FileSize = -1;
}

protected static ImageSource InitializeIsEmptyFolder(string fullPath) {
if (IsEmptyFolderDictionary.TryGetValue(fullPath, out var isEmpty)) {
isEmptyFolder = isEmpty;
Icon = isEmpty ? EmptyFolderDrawingImage : FolderDrawingImage;
} else {
Icon = FolderDrawingImage;
return isEmpty ? EmptyFolderDrawingImage : FolderDrawingImage;
}
return FolderDrawingImage;
}

public override string DisplayText => Name;

public override void LoadAttributes(LoadDetailsOptions options) {
isEmptyFolder = FolderUtils.IsEmptyFolder(FullPath);
Type = isEmptyFolder ? "EmptyFolder".L() : "Folder".L();
IsEmptyFolderDictionary.Add(FullPath, isEmptyFolder);
Type = isEmptyFolder ? "EmptyFolder".L() : "Folder".L();
var directoryInfo = new DirectoryInfo(FullPath);
DateModified = directoryInfo.LastWriteTime;
DateCreated = directoryInfo.CreationTime;
Expand Down

0 comments on commit 92d1713

Please sign in to comment.