diff --git a/ExplorerEx/Assets/Geometries.xaml b/ExplorerEx/Assets/Geometries.xaml
index b0a790f..23dbf23 100644
--- a/ExplorerEx/Assets/Geometries.xaml
+++ b/ExplorerEx/Assets/Geometries.xaml
@@ -235,10 +235,10 @@
-
+
-
+
@@ -1005,6 +1005,129 @@
+ M532.5 513h-206V495h206A19.6 19.6 0 00552 475.5v-412A19.6 19.6 0 00532.5 44h-412A19.6 19.6 0 00101 63.5v412A19.6 19.6 0 00120.5 495h8.7v18h-8.7A37.6 37.6 0 0183 475.5v-412A37.6 37.6 0 01120.5 26h412A37.6 37.6 0 01570 63.5v412A37.6 37.6 0 01532.5 513ZM426.3 462.2l-64.8-41C209.4 573.4 40 582 40 582c153-34.8 224.4-222.2 224.4-222.2l-64.8-41 216-90.5 10.6 234Z
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1013,6 +1136,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
M 955.1 433.2 H 301.3 c -17.7 0 -25.6 -21.7 -13.8 -33.5 l 189 -189 c 11.8 -11.8 11.8 -29.5 0 -41.4 L 433.2 126 c -11.8 -11.8 -29.5 -11.8 -41.4 0 L 47.3 470.6 c -11.8 11.8 -11.8 29.5 0 41.4 l 344.6 344.6 c 11.8 11.8 29.5 11.8 41.4 0 l 41.4 -41.4 c 11.8 -11.8 11.8 -29.5 0 -41.4 l -189 -189 c -11.8 -11.8 -3.9 -33.5 13.8 -33.5 h 653.8 c 15.8 0 29.5 -13.8 29.5 -29.5 v -59.1 c 2 -15.8 -11.8 -29.5 -27.6 -29.5 z
M -955.1 433.2 H -301.3 c 17.7 0 25.6 -21.7 13.8 -33.5 l -189 -189 c -11.8 -11.8 -11.8 -29.5 0 -41.4 L -433.2 126 c 11.8 -11.8 29.5 -11.8 41.4 0 L -47.3 470.6 c 11.8 11.8 11.8 29.5 0 41.4 l -344.6 344.6 c -11.8 11.8 -29.5 11.8 -41.4 0 l -41.4 -41.4 c -11.8 -11.8 -11.8 -29.5 0 -41.4 l 189 -189 c 11.8 -11.8 3.9 -33.5 -13.8 -33.5 h -653.8 c -15.8 0 -29.5 -13.8 -29.5 -29.5 v -59.1 c -2 -15.8 11.8 -29.5 27.6 -29.5 z
M 414 809.7 V 155.9 c 0 -17.7 -21.7 -25.6 -33.5 -13.8 l -189 189 c -11.8 11.8 -29.5 11.8 -41.4 0 l -43.3 -43.3 c -11.8 -11.8 -11.8 -29.5 0 -41.4 l 344.6 -344.5 c 11.8 -11.8 29.5 -11.8 41.4 0 l 344.6 344.6 c 11.8 11.8 11.8 29.5 0 41.4 L 796 329.3 c -11.8 11.8 -29.5 11.8 -41.4 0 l -189 -189 c -11.8 -11.8 -33.5 -3.9 -33.5 13.8 v 653.8 c 0 15.8 -13.8 29.5 -29.5 29.5 h -59.1 c -15.8 2 -29.5 -11.8 -29.5 -27.6 Z
diff --git a/ExplorerEx/Assets/Settings.xml b/ExplorerEx/Assets/Settings.xml
index c88a1c6..bae3c97 100644
--- a/ExplorerEx/Assets/Settings.xml
+++ b/ExplorerEx/Assets/Settings.xml
@@ -1,33 +1,42 @@
-
- -
+
-
+
+
+
+
+ -
- -
-
-
-
+
-
+
+
+ -
+
+
+
+
- -
-
+
-
+
-
+
+
-
-
+
+
\ No newline at end of file
diff --git a/ExplorerEx/Assets/Svg.zip b/ExplorerEx/Assets/Svg.zip
deleted file mode 100644
index 7f645d6..0000000
Binary files a/ExplorerEx/Assets/Svg.zip and /dev/null differ
diff --git a/ExplorerEx/Assets/Svg/Background.svg b/ExplorerEx/Assets/Svg/Background.svg
new file mode 100644
index 0000000..c9eaf3a
--- /dev/null
+++ b/ExplorerEx/Assets/Svg/Background.svg
@@ -0,0 +1,3 @@
+
diff --git a/ExplorerEx/Assets/Svg/Blur.svg b/ExplorerEx/Assets/Svg/Blur.svg
new file mode 100644
index 0000000..619cdc2
--- /dev/null
+++ b/ExplorerEx/Assets/Svg/Blur.svg
@@ -0,0 +1,3 @@
+
diff --git a/ExplorerEx/Assets/Svg/Click.svg b/ExplorerEx/Assets/Svg/Click.svg
new file mode 100644
index 0000000..aa0e8c4
--- /dev/null
+++ b/ExplorerEx/Assets/Svg/Click.svg
@@ -0,0 +1,3 @@
+
diff --git a/ExplorerEx/Assets/Svg/Color.svg b/ExplorerEx/Assets/Svg/Color.svg
new file mode 100644
index 0000000..323de5c
--- /dev/null
+++ b/ExplorerEx/Assets/Svg/Color.svg
@@ -0,0 +1,3 @@
+
diff --git a/ExplorerEx/Assets/Svg/Eye.svg b/ExplorerEx/Assets/Svg/Eye.svg
new file mode 100644
index 0000000..af3bf7a
--- /dev/null
+++ b/ExplorerEx/Assets/Svg/Eye.svg
@@ -0,0 +1,3 @@
+
diff --git a/ExplorerEx/Assets/Svg/Image.svg b/ExplorerEx/Assets/Svg/Image.svg
new file mode 100644
index 0000000..0ce5b6d
--- /dev/null
+++ b/ExplorerEx/Assets/Svg/Image.svg
@@ -0,0 +1,3 @@
+
diff --git a/ExplorerEx/Assets/Svg/Language.svg b/ExplorerEx/Assets/Svg/Language.svg
new file mode 100644
index 0000000..866d325
--- /dev/null
+++ b/ExplorerEx/Assets/Svg/Language.svg
@@ -0,0 +1,3 @@
+
diff --git a/ExplorerEx/Assets/Svg/Share.svg b/ExplorerEx/Assets/Svg/Share.svg
index fac98ef..737dfe1 100644
--- a/ExplorerEx/Assets/Svg/Share.svg
+++ b/ExplorerEx/Assets/Svg/Share.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/ExplorerEx/Assets/Svg/TextEditor.svg b/ExplorerEx/Assets/Svg/TextEditor.svg
new file mode 100644
index 0000000..9822a01
--- /dev/null
+++ b/ExplorerEx/Assets/Svg/TextEditor.svg
@@ -0,0 +1,3 @@
+
diff --git a/ExplorerEx/Command/FileItemCommand.cs b/ExplorerEx/Command/FileItemCommand.cs
index 9297b18..ac41c68 100644
--- a/ExplorerEx/Command/FileItemCommand.cs
+++ b/ExplorerEx/Command/FileItemCommand.cs
@@ -130,7 +130,7 @@ public async void Execute(object? param) {
}
var items = Items;
switch (items.Count) {
- case <= 0:
+ case 0:
return;
case 1:
FileTabControl.MouseOverTabControl?.SelectedTab.StartRename(items[0]);
@@ -141,16 +141,20 @@ public async void Execute(object? param) {
}
break;
}
- case "Delete": // 删除一个或多个文件,按住shift就是强制删除
+ case "Delete": { // 删除一个或多个文件,按住shift就是强制删除
if (Folder.IsReadonly) {
break;
}
- if ((Keyboard.Modifiers & ModifierKeys.Shift) != ModifierKeys.Shift) { // 没有按Shift
+ var items = Items;
+ if (items.Count == 0) {
+ break;
+ }
+ if ((Keyboard.Modifiers & ModifierKeys.Shift) != ModifierKeys.Shift) { // 没有按Shift
if (!ContentDialog.ShowWithDefault(Settings.CommonSettings.DontAskWhenRecycle, "#AreYouSureToRecycleTheseFiles".L())) {
return;
}
try {
- await FileUtils.FileOperation(FileOpType.Delete, Items.Where(item => item is FileSystemItem).Select(item => item.FullPath).ToArray());
+ await FileUtils.FileOperation(FileOpType.Delete, items.Where(item => item is FileSystemItem).Select(item => item.FullPath).ToArray());
} catch (Exception e) {
Logger.Exception(e);
}
@@ -159,7 +163,7 @@ public async void Execute(object? param) {
return;
}
var failedFiles = new List();
- foreach (var item in Items) {
+ foreach (var item in items) {
if (item is FileSystemItem fsi) {
try {
if (fsi.IsFolder) {
@@ -178,6 +182,7 @@ public async void Execute(object? param) {
}
}
break;
+ }
case "AddToBookmarks":
TabControlProvider.Invoke()?.MainWindow.AddToBookmarks(Items.Select(i => i.FullPath).ToArray());
break;
diff --git a/ExplorerEx/Converter/DictionaryConverter.cs b/ExplorerEx/Converter/DictionaryConverter.cs
index 37d04ff..1f1e8c2 100644
--- a/ExplorerEx/Converter/DictionaryConverter.cs
+++ b/ExplorerEx/Converter/DictionaryConverter.cs
@@ -8,10 +8,10 @@
namespace ExplorerEx.Converter;
public class DependencyKeyValuePair : DependencyObject {
- public object Key { get; set; }
+ public object Key { get; set; } = null!;
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
- "Value", typeof(object), typeof(DependencyKeyValuePair), new PropertyMetadata(default(object)));
+ nameof(Value), typeof(object), typeof(DependencyKeyValuePair), new PropertyMetadata(default(object)));
public object Value {
get => GetValue(ValueProperty);
@@ -42,7 +42,7 @@ public DictionaryConverter() {
};
}
- public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
+ public object? Convert(object? value, Type targetType, object parameter, CultureInfo culture) {
if (value == null) {
return null;
}
@@ -53,6 +53,6 @@ public object Convert(object value, Type targetType, object parameter, CultureIn
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
- throw new NotImplementedException();
+ throw new InvalidOperationException();
}
}
\ No newline at end of file
diff --git a/ExplorerEx/Converter/FileAssocTemplateSelector.cs b/ExplorerEx/Converter/FileAssocTemplateSelector.cs
index d78c568..51d99dd 100644
--- a/ExplorerEx/Converter/FileAssocTemplateSelector.cs
+++ b/ExplorerEx/Converter/FileAssocTemplateSelector.cs
@@ -2,14 +2,16 @@
using System.Windows.Controls;
using ExplorerEx.Model;
-namespace ExplorerEx.Converter;
+namespace ExplorerEx.Converter;
-internal class FileAssocTemplateSelector : StyleSelector {
- public Style DefaultStyle { get; set; }
+internal class FileAssocTemplateSelector : StyleSelector
+{
+ public Style DefaultStyle { get; set; } = null!;
- public Style CustomStyle { get; set; }
+ public Style CustomStyle { get; set; } = null!;
- public override Style SelectStyle(object item, DependencyObject container) {
- return item is FileAssocItem ? CustomStyle : DefaultStyle;
- }
+ public override Style SelectStyle(object item, DependencyObject container)
+ {
+ return item is FileAssocItem ? CustomStyle : DefaultStyle;
+ }
}
\ No newline at end of file
diff --git a/ExplorerEx/Converter/FileViewItemDetailsConverter.cs b/ExplorerEx/Converter/FileViewItemDetailsConverter.cs
index b3eaee2..a46d40a 100644
--- a/ExplorerEx/Converter/FileViewItemDetailsConverter.cs
+++ b/ExplorerEx/Converter/FileViewItemDetailsConverter.cs
@@ -22,8 +22,11 @@ public object ConvertBack(object value, Type targetType, object parameter, Cultu
internal class ItemsCount2TextConverter : IValueConverter {
public object? Convert(object value, Type targetType, object parameter, CultureInfo culture) {
- if (value is int i and > 0) {
- return string.Format("...Items".L(), i);
+ if (value is int i) {
+ if (i > 1) {
+ return string.Format("...Items".L(), i);
+ }
+ return string.Format("...Item".L(), i);
}
return null;
}
diff --git a/ExplorerEx/Converter/SettingsPanelItemTemplateSelector.cs b/ExplorerEx/Converter/SettingsPanelItemTemplateSelector.cs
new file mode 100644
index 0000000..7e7f5eb
--- /dev/null
+++ b/ExplorerEx/Converter/SettingsPanelItemTemplateSelector.cs
@@ -0,0 +1,26 @@
+using System.Windows;
+using System.Windows.Controls;
+
+namespace ExplorerEx.Converter;
+
+internal class SettingsPanelItemTemplateSelector : DataTemplateSelector {
+ public DataTemplate SettingsSelectItemTemplate { get; set; } = null!;
+
+ public DataTemplate SettingsStringItemTemplate { get; set; } = null!;
+
+ public DataTemplate SettingsBooleanItemTemplate { get; set; } = null!;
+
+ public DataTemplate SettingsNumberItemTemplate { get; set; } = null!;
+
+ public DataTemplate SettingsExpanderTemplate { get; set; } = null!;
+
+ public override DataTemplate SelectTemplate(object item, DependencyObject container) {
+ return item switch {
+ SettingsSelectItem => SettingsSelectItemTemplate,
+ SettingsStringItem => SettingsStringItemTemplate,
+ SettingsBooleanItem => SettingsBooleanItemTemplate,
+ SettingsNumberItem => SettingsNumberItemTemplate,
+ _ => SettingsExpanderTemplate
+ };
+ }
+}
\ No newline at end of file
diff --git a/ExplorerEx/Database/EntityFramework/BookmarkEfContext.cs b/ExplorerEx/Database/EntityFramework/BookmarkEfContext.cs
index 525e383..4815a0c 100644
--- a/ExplorerEx/Database/EntityFramework/BookmarkEfContext.cs
+++ b/ExplorerEx/Database/EntityFramework/BookmarkEfContext.cs
@@ -1,8 +1,8 @@
using System;
-using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
+using System.Linq.Expressions;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows;
@@ -31,7 +31,18 @@ public BookmarkEfContext() {
dbPath = Path.Combine(path, "BookMarks.db");
}
- public async Task LoadDataBase() {
+ protected override void OnConfiguring(DbContextOptionsBuilder ob) {
+ ob.UseSqlite($"Data Source={dbPath}");
+ }
+
+ protected override void OnModelCreating(ModelBuilder modelBuilder) {
+ modelBuilder.Entity().HasOne(b => b.Category)
+ .WithMany(cb => cb.Children).HasForeignKey(b => b.CategoryForeignKey);
+ }
+
+ #region Interfaces
+
+ public async Task LoadAsync() {
try {
await Database.EnsureCreatedAsync();
await BookmarkCategoryDbSet.LoadAsync();
@@ -60,69 +71,29 @@ await Task.Run(() => {
}
}
- protected override void OnConfiguring(DbContextOptionsBuilder ob) {
- ob.UseSqlite($"Data Source={dbPath}");
- }
-
- protected override void OnModelCreating(ModelBuilder modelBuilder) {
- modelBuilder.Entity().HasOne(b => b.Category)
- .WithMany(cb => cb.Children).HasForeignKey(b => b.CategoryForeignKey);
- }
+ public void Save() => base.SaveChanges();
- #region Interfaces
+ public Task SaveAsync() => base.SaveChangesAsync();
public void Add(BookmarkItem bookmark) {
BookmarkDbSet.Add(bookmark);
}
- public Task AddAsync(BookmarkItem bookmark) {
- return BookmarkDbSet.AddAsync(bookmark).AsTask();
- }
public void Add(BookmarkCategory category) {
BookmarkCategoryDbSet.Add(category);
}
- public Task AddAsync(BookmarkCategory category) {
- return BookmarkCategoryDbSet.AddAsync(category).AsTask();
- }
-
- public Task LoadAsync() {
- throw new NotImplementedException();
- }
- public void Save() {
- base.SaveChanges();
- }
+ public void Remove(BookmarkItem bookmark) => base.Remove(bookmark);
- public Task SaveAsync() {
- return base.SaveChangesAsync();
- }
+ public bool Contains(BookmarkItem bookmark) => BookmarkDbSet.Contains(bookmark);
- public void Remove(BookmarkItem bookmark) {
- base.Remove(bookmark);
- }
-
- public bool Contains(BookmarkItem bookmark) {
- return BookmarkDbSet.Contains(bookmark);
- }
+ public bool Any(Expression> match) => BookmarkDbSet.Any(match);
- public bool Any(Func match) {
- return BookmarkDbSet.Any(match);
- }
-
- public ObservableCollection GetBindable() {
- return BookmarkCategoryDbSet.Local.ToObservableCollection();
- }
-
- #region ProbablyModify
- public BookmarkCategory? FirstOrDefault(Func match) {
- return BookmarkCategoryDbSet.FirstOrDefault(match);
- }
-
- public BookmarkItem? FirstOrDefault(Func match) {
- return BookmarkDbSet.FirstOrDefault(match);
- }
-
- #endregion
+ public ObservableCollection GetBindable() => BookmarkCategoryDbSet.Local.ToObservableCollection();
+
+ public BookmarkCategory? FirstOrDefault(Expression> match) => BookmarkCategoryDbSet.FirstOrDefault(match);
+ public BookmarkItem? FirstOrDefault(Expression> match) => BookmarkDbSet.FirstOrDefault(match);
+
#endregion
}
\ No newline at end of file
diff --git a/ExplorerEx/Database/EntityFramework/FileViewEfContext.cs b/ExplorerEx/Database/EntityFramework/FileViewEfContext.cs
index cd85b56..12d3130 100644
--- a/ExplorerEx/Database/EntityFramework/FileViewEfContext.cs
+++ b/ExplorerEx/Database/EntityFramework/FileViewEfContext.cs
@@ -1,7 +1,7 @@
using System;
-using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Linq.Expressions;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows;
@@ -29,18 +29,6 @@ protected override void OnConfiguring(DbContextOptionsBuilder ob) {
ob.UseSqlite($"Data Source={dbPath}");
}
- public bool Any(Func match) {
- return FileViewDbSet.Any(match);
- }
-
- public void Add(FileView item) {
- FileViewDbSet.Add(item);
- }
-
- public Task AddAsync(FileView item) {
- return FileViewDbSet.AddAsync(item).AsTask();
- }
-
public async Task LoadAsync() {
try {
await Database.EnsureCreatedAsync();
@@ -51,19 +39,19 @@ public async Task LoadAsync() {
}
}
- public void Save() {
- base.SaveChanges();
- }
+ public void Save() => base.SaveChanges();
- public Task SaveAsync() {
- return base.SaveChangesAsync();
- }
+ public Task SaveAsync() => base.SaveChangesAsync();
- public FileView? FirstOrDefault(Func match) {
- return FileViewDbSet.FirstOrDefault(match);
- }
+ public bool Any(Expression> match) => FileViewDbSet.Any(match);
- public bool Contains(FileView fileView) {
- return FileViewDbSet.Contains(fileView);
+ public void Add(FileView item) => FileViewDbSet.Add(item);
+
+ public void Update(FileView item) {
+ // No need to update
}
+
+ public FileView? FirstOrDefault(Expression> match) => FileViewDbSet.FirstOrDefault(match);
+
+ public bool Contains(FileView fileView) => FileViewDbSet.Contains(fileView);
}
\ No newline at end of file
diff --git a/ExplorerEx/Database/Interface/IBookmarkDbContext.cs b/ExplorerEx/Database/Interface/IBookmarkDbContext.cs
index 3080f8d..741c42b 100644
--- a/ExplorerEx/Database/Interface/IBookmarkDbContext.cs
+++ b/ExplorerEx/Database/Interface/IBookmarkDbContext.cs
@@ -1,23 +1,20 @@
using System;
-using System.Collections.Generic;
using System.Collections.ObjectModel;
-using System.Threading.Tasks;
+using System.Linq.Expressions;
using ExplorerEx.Model;
namespace ExplorerEx.Database.Interface;
public interface IBookmarkDbContext : IDatabase {
void Add(BookmarkItem bookmark);
- Task AddAsync(BookmarkItem bookmark);
- public BookmarkItem? FirstOrDefault(Func match);
+ public BookmarkItem? FirstOrDefault(Expression> match);
void Remove(BookmarkItem bookmark);
bool Contains(BookmarkItem bookmark);
- bool Any(Func match);
+ bool Any(Expression> match);
- BookmarkCategory? FirstOrDefault(Func match);
+ BookmarkCategory? FirstOrDefault(Expression> match);
void Add(BookmarkCategory category);
- Task AddAsync(BookmarkCategory category);
ObservableCollection GetBindable();
}
\ No newline at end of file
diff --git a/ExplorerEx/Database/Interface/IDatabase.cs b/ExplorerEx/Database/Interface/IDatabase.cs
index 52a157a..60e45ef 100644
--- a/ExplorerEx/Database/Interface/IDatabase.cs
+++ b/ExplorerEx/Database/Interface/IDatabase.cs
@@ -1,4 +1,5 @@
-using System.Threading.Tasks;
+using ExplorerEx.Model;
+using System.Threading.Tasks;
namespace ExplorerEx.Database.Interface;
diff --git a/ExplorerEx/Database/Interface/IDbContext.cs b/ExplorerEx/Database/Interface/IDbContext.cs
new file mode 100644
index 0000000..4da77eb
--- /dev/null
+++ b/ExplorerEx/Database/Interface/IDbContext.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Linq.Expressions;
+
+namespace ExplorerEx.Database.Interface;
+
+public interface IDbContext {
+ void Add(T item);
+ public T? FirstOrDefault(Expression> match);
+ void Remove(T item);
+ bool Contains(T item);
+ bool Any(Expression> match);
+
+ int Count();
+}
\ No newline at end of file
diff --git a/ExplorerEx/Database/Interface/IFileViewDbContext.cs b/ExplorerEx/Database/Interface/IFileViewDbContext.cs
index fcc0959..c5dc820 100644
--- a/ExplorerEx/Database/Interface/IFileViewDbContext.cs
+++ b/ExplorerEx/Database/Interface/IFileViewDbContext.cs
@@ -1,14 +1,17 @@
using System;
-using System.Threading.Tasks;
+using System.Linq.Expressions;
using ExplorerEx.Model;
namespace ExplorerEx.Database.Interface;
public interface IFileViewDbContext : IDatabase {
- FileView? FirstOrDefault(Func match);
+ FileView? FirstOrDefault(Expression> match);
bool Contains(FileView fileView);
- bool Any(Func match);
-
+ bool Any(Expression> match);
void Add(FileView item);
- Task AddAsync(FileView item);
+ ///
+ /// 由于不带Cache跟踪,所以需要手动更新数据
+ ///
+ ///
+ void Update(FileView item);
}
\ No newline at end of file
diff --git a/ExplorerEx/Database/SqlSugar/BookmarkSugarContext.cs b/ExplorerEx/Database/SqlSugar/BookmarkSugarContext.cs
index 9258d34..13c1180 100644
--- a/ExplorerEx/Database/SqlSugar/BookmarkSugarContext.cs
+++ b/ExplorerEx/Database/SqlSugar/BookmarkSugarContext.cs
@@ -1,7 +1,6 @@
using System;
-using System.Collections.Generic;
using System.Collections.ObjectModel;
-using System.Linq;
+using System.Linq.Expressions;
using System.Threading.Tasks;
using System.Windows;
using ExplorerEx.Database.Interface;
@@ -10,37 +9,34 @@
namespace ExplorerEx.Database.SqlSugar;
-public class BookmarkSugarContext : SugarContext, IBookmarkDbContext {
- private readonly SugarCache itemSugarCache;
- private readonly SugarCache categorySugarCache;
-
-
- public BookmarkSugarContext() : base("BookMarks.db") {
- itemSugarCache = new SugarCache(ConnectionClient);
- categorySugarCache = new SugarCache(ConnectionClient,
- new SugarStrategy(itemSugarCache, (category, item) => {
- if (item.CategoryForeignKey == category.Name) {
- item.Category = category;
- category.Children?.Add(item);
- }
- }));
+public class BookmarkSugarContext : IBookmarkDbContext {
+ private readonly CachedSugarContext bookmarkCtx;
+ private readonly CachedSugarContext categoryCtx;
+
+ public BookmarkSugarContext() {
+ categoryCtx = new CachedSugarContext("BookMarks.db");
+ bookmarkCtx = new CachedSugarContext("BookMarks.db");
+ //categorySugarCache = new SugarCache(ConnectionClient,
+ // new SugarStrategy(itemSugarCache, (category, item) => {
+ // if (item.CategoryForeignKey == category.Name) {
+ // item.Category = category;
+ // category.Children?.Add(item);
+ // }
+ // }));
}
- public new Task LoadAsync() {
- return Task.Run(() => {
+ public async Task LoadAsync() {
+ await categoryCtx.LoadAsync();
+ await bookmarkCtx.LoadAsync();
+ await Task.Run(() => {
try {
- ConnectionClient.DbMaintenance.CreateDatabase();
- ConnectionClient.CodeFirst.InitTables();
- itemSugarCache.LoadDatabase();
- categorySugarCache.LoadDatabase();
-
- if (categorySugarCache.Count() == 0) {
+ if (categoryCtx.Count() == 0) {
var defaultCategory = new BookmarkCategory("DefaultBookmark".L());
- categorySugarCache.Add(defaultCategory);
- categorySugarCache.Save();
- itemSugarCache.Add(new BookmarkItem(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Documents".L(), defaultCategory));
- itemSugarCache.Add(new BookmarkItem(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Desktop".L(), defaultCategory));
- itemSugarCache.Save();
+ categoryCtx.Add(defaultCategory);
+ categoryCtx.Save();
+ bookmarkCtx.Add(new BookmarkItem(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Documents".L(), defaultCategory));
+ bookmarkCtx.Add(new BookmarkItem(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Desktop".L(), defaultCategory));
+ bookmarkCtx.Save();
}
} catch (Exception e) {
MessageBox.Show("无法加载数据库,可能是权限不够或者数据库版本过旧,请删除Data文件夹后再试一次。\n错误为:" + e.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
@@ -49,54 +45,26 @@ public BookmarkSugarContext() : base("BookMarks.db") {
});
}
- public void Add(BookmarkItem bookmark) {
- itemSugarCache.Add(bookmark);
- }
+ public void Add(BookmarkItem bookmark) => bookmarkCtx.Add(bookmark);
- public void Add(BookmarkCategory category) {
- categorySugarCache.Add(category);
- }
+ public void Add(BookmarkCategory category) => categoryCtx.Add(category);
- public Task AddAsync(BookmarkItem bookmark) {
- return Task.Run(() => Add(bookmark));
- }
+ public bool Contains(BookmarkItem bookmark) => bookmarkCtx.Contains(bookmark);
- public Task AddAsync(BookmarkCategory category) {
- return Task.Run(() => Add(category));
- }
+ public bool Any(Expression> match) => bookmarkCtx.Any(match);
- public bool Contains(BookmarkItem bookmark) {
- return itemSugarCache.Contains(bookmark);
- }
+ public BookmarkCategory? FirstOrDefault(Expression> match) => categoryCtx.FirstOrDefault(match);
- public bool Any(Func match) {
- return itemSugarCache.Any(match);
- }
-
- public BookmarkCategory? FirstOrDefault(Func match) {
- return categorySugarCache.FirstOrDefault(match);
- }
-
- public BookmarkItem? FirstOrDefault(Func match) {
- return itemSugarCache.FirstOrDefault(match);
- }
+ public BookmarkItem? FirstOrDefault(Expression> match) => bookmarkCtx.FirstOrDefault(match);
- public ObservableCollection GetBindable() {
- var ret = new ObservableCollection();
- categorySugarCache.ForEach(x => ret.Add(x));
- return ret;
- }
+ public ObservableCollection GetBindable() => categoryCtx.GetBindable();
- public void Remove(BookmarkItem bookmark) {
- itemSugarCache.Remove(bookmark);
- }
+ public void Remove(BookmarkItem bookmark) => bookmarkCtx.Remove(bookmark);
- public override void Save() {
- itemSugarCache.Save();
- categorySugarCache.Save();
+ public void Save() {
+ categoryCtx.Save();
+ bookmarkCtx.Save();
}
- public override Task SaveAsync() {
- return Task.Run(Save);
- }
+ public Task SaveAsync() => Task.Run(Save); // TODO: Thread safe???
}
\ No newline at end of file
diff --git a/ExplorerEx/Database/SqlSugar/FileViewSugarContext.cs b/ExplorerEx/Database/SqlSugar/FileViewSugarContext.cs
index 971efe7..77f7881 100644
--- a/ExplorerEx/Database/SqlSugar/FileViewSugarContext.cs
+++ b/ExplorerEx/Database/SqlSugar/FileViewSugarContext.cs
@@ -1,50 +1,15 @@
-using System;
-using System.Collections.Generic;
-using System.Threading.Tasks;
-using ExplorerEx.Database.Interface;
+using ExplorerEx.Database.Interface;
using ExplorerEx.Model;
namespace ExplorerEx.Database.SqlSugar;
-public class FileViewSugarContext : SugarContext, IFileViewDbContext {
- private readonly SugarCache fileSugarCache;
+///
+/// 这个不需要Cache
+///
+public class FileViewSugarContext : SugarContext, IFileViewDbContext {
+ public FileViewSugarContext() : base("FileViews.db") { }
- public FileViewSugarContext() : base("FileViews.db") {
- fileSugarCache = new SugarCache(ConnectionClient);
- }
-
- public override Task LoadAsync() {
- return Task.Run(() => {
- ConnectionClient.CodeFirst.InitTables();
- fileSugarCache.LoadDatabase();
- });
- }
-
- public bool Any(Func match) {
- throw new NotImplementedException();
- }
-
- public void Add(FileView item) {
- fileSugarCache.Add(item);
- }
-
- public Task AddAsync(FileView item) {
- return Task.Run(() => Add(item));
- }
-
- public FileView? FirstOrDefault(Func match) {
- return fileSugarCache.FirstOrDefault(match);
- }
-
- public bool Contains(FileView fileView) {
- return fileSugarCache.Contains(fileView);
- }
-
- public override void Save() {
- fileSugarCache.Save();
- }
-
- public override Task SaveAsync() {
- return Task.Run(Save);
+ public void Update(FileView item) {
+ ConnectionClient.Updateable().Where(i => i.FullPath == item.FullPath);
}
}
\ No newline at end of file
diff --git a/ExplorerEx/Database/SqlSugar/SqlSugarHelper.cs b/ExplorerEx/Database/SqlSugar/SqlSugarHelper.cs
new file mode 100644
index 0000000..56634bd
--- /dev/null
+++ b/ExplorerEx/Database/SqlSugar/SqlSugarHelper.cs
@@ -0,0 +1,55 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using SqlSugar;
+
+namespace ExplorerEx.Database.SqlSugar;
+
+///
+/// 实验性质
+///
+public static class SqlSugarHelper {
+ private static readonly Dictionary TypeCache;
+ private static readonly MethodInfo GetCustomTypeByClassInfo;
+
+ static SqlSugarHelper() {
+ TypeCache = (Dictionary)typeof(InstanceFactory).GetField("typeCache", BindingFlags.NonPublic | BindingFlags.Static)!.GetValue(null)!;
+ GetCustomTypeByClassInfo = typeof(InstanceFactory).GetMethod("GetCustomTypeByClass", BindingFlags.NonPublic | BindingFlags.Static)!;
+ }
+
+ public static object Queryable(this SqlSugarClient client, Type type) {
+ client.InitMappingInfo(type);
+ return GetCacheInstance(GetClassName(client.CurrentConnectionConfig.DbType.ToString(), "Queryable"), type);
+ }
+
+ private static string GetClassName(string type, string name) {
+ return type switch {
+ "MySqlConnector" => "SqlSugar.MySqlConnector.MySql" + name,
+ "Access" => "SqlSugar.Access.Access" + name,
+ "ClickHouse" => "SqlSugar.ClickHouse.ClickHouse" + name,
+ _ => type == "Custom" ? InstanceFactory.CustomNamespace + "." + InstanceFactory.CustomDbName + name : "SqlSugar." + type + name
+ };
+ }
+
+ private static object GetCacheInstance(string className, Type type) {
+ var key = className + type;
+ lock (TypeCache) {
+ if (TypeCache.ContainsKey(key)) {
+ type = TypeCache[key];
+ } else {
+ if (string.IsNullOrEmpty(InstanceFactory.CustomDllName)) {
+ type = Type.GetType(className + "`1", true)!.MakeGenericType(type);
+ } else {
+ var customTypeByClass = (Type?)GetCustomTypeByClassInfo.Invoke(null, new object[] { className + "`1" });
+ if (customTypeByClass != null) {
+ type = customTypeByClass.MakeGenericType(type);
+ }
+ }
+ if (!TypeCache.ContainsKey(key)) {
+ TypeCache.Add(key, type);
+ }
+ }
+ }
+ return Activator.CreateInstance(type, true)!;
+ }
+}
\ No newline at end of file
diff --git a/ExplorerEx/Database/SqlSugar/SugarCache.cs b/ExplorerEx/Database/SqlSugar/SugarCache.cs
index 953d56a..f47d227 100644
--- a/ExplorerEx/Database/SqlSugar/SugarCache.cs
+++ b/ExplorerEx/Database/SqlSugar/SugarCache.cs
@@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Linq;
using System.Reflection;
-using System.Runtime.InteropServices;
using Castle.DynamicProxy;
using SqlSugar;
@@ -19,13 +19,9 @@ public abstract class SugarCacheBase {
protected bool IsLoaded;
protected SugarCacheBase(Type type) {
- if (!type.IsClass || Caches.ContainsKey(type)) {
- throw new ExternalException("This class has already been proxied");
- }
+ Debug.Assert(!type.IsClass || Caches.ContainsKey(type));
Caches.Add(type, this);
}
-
- public abstract void LoadDatabase();
}
///
@@ -75,7 +71,7 @@ public SugarCache(ISqlSugarClient db) : base(typeof(T)) {
interceptor = new DbModelInterceptor(this);
}
- public override void LoadDatabase() {
+ public void LoadDatabase() {
if (!IsLoaded) {
var interceptor = new DbModelInterceptor(this);
db.Queryable().ForEach(x => locals.Add(Generator.CreateClassProxyWithTarget(x, interceptor)));
@@ -83,13 +79,9 @@ public override void LoadDatabase() {
}
}
- public T? FirstOrDefault(Func match) {
- return locals.FirstOrDefault(match);
- }
+ public T? FirstOrDefault(Func match) => locals.FirstOrDefault(match);
- public bool Contains(T item) {
- return locals.Contains(item);
- }
+ public bool Contains(T item) => locals.Contains(item);
public void ForEach(Action action) {
foreach (var local in locals) {
@@ -97,9 +89,7 @@ public void ForEach(Action action) {
}
}
- public bool Any(Func match) {
- return locals.Any(match);
- }
+ public bool Any(Func match) => locals.Any(match);
public void Add(T item) {
// TODO: 目前是加锁,是否需要一个并行方法?(并行参考Utils.Collections.ConcurrentObservableCollection)
@@ -110,6 +100,18 @@ public void Add(T item) {
}
}
+ ///
+ /// 标记为已更改
+ ///
+ /// 为Proxy
+ private void MarkAsChanged(T item) {
+ lock (lockObj) {
+ if (!changes.Contains(item) && !deletes.Contains(item) && locals.Contains(item)) {
+ changes.Add(item);
+ }
+ }
+ }
+
public void Remove(T item) {
lock (lockObj) {
if (!adds.Remove(item) && locals.Remove(item)) {
@@ -119,9 +121,7 @@ public void Remove(T item) {
}
}
- public int Count() {
- return locals.Count;
- }
+ public int Count() => locals.Count;
public void Save() {
lock (lockObj) {
@@ -158,71 +158,14 @@ public void Intercept(IInvocation invocation) {
// 这里只用一个简单的比对即可
// 至于下面的Contains和Add,目前是HashSet,性能很高
// 可以考虑使用并发Add
+
if (invocation.Method.Attributes.HasFlag(MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.SpecialName)) {
- var p = (T)invocation.Proxy;
- if (!cache.changes.Contains(p) && !cache.deletes.Contains(p) && cache.locals.Contains(p)) {
- cache.changes.Add(p);
+ if (invocation.Method.ReturnType == typeof(void)) {
+ cache.MarkAsChanged((T)invocation.Proxy); // set
+ } else {
+
}
}
}
}
}
-
-///
-/// 含有依赖关系的缓存
-///
-///
-///
-public class SugarCache : SugarCache
- where TSelf : class, new()
- where TSub : class, new() {
-
- private readonly SugarStrategy strategy;
-
- public SugarCache(ISqlSugarClient db, SugarStrategy strategy) : base(db) {
- this.strategy = strategy;
- }
-
- public void LoadDataBase() {
- if (!IsLoaded) {
- var interceptor = new DbModelInterceptor(this);
- db.Queryable().ForEach(x => {
- strategy.Source.ForEach(v => strategy.Action(x, v));
- locals.Add(Generator.CreateClassProxyWithTarget(x, interceptor));
- });
- IsLoaded = true;
- }
- }
-}
-
-///
-/// 含有更多依赖关系的缓存
-///
-///
-///
-///
-public class SugarCache : SugarCache
- where TSelf : class, new()
- where TSub1 : class, new()
- where TSub2 : class, new() {
- private readonly SugarStrategy strategy1;
- private readonly SugarStrategy strategy2;
-
- public SugarCache(ISqlSugarClient db, SugarStrategy strategy1, SugarStrategy strategy2) : base(db) {
- this.strategy1 = strategy1;
- this.strategy2 = strategy2;
- }
-
- public void LoadDataBase() {
- if (!IsLoaded) {
- var interceptor = new DbModelInterceptor(this);
- db.Queryable().ForEach(x => {
- strategy1.Source.ForEach(v => strategy1.Action(x, v));
- strategy2.Source.ForEach(v => strategy2.Action(x, v));
- locals.Add(Generator.CreateClassProxyWithTarget(x, interceptor));
- });
- IsLoaded = true;
- }
-
- }
-}
\ No newline at end of file
diff --git a/ExplorerEx/Database/SqlSugar/SugarContext.cs b/ExplorerEx/Database/SqlSugar/SugarContext.cs
index 33252a9..91b98d6 100644
--- a/ExplorerEx/Database/SqlSugar/SugarContext.cs
+++ b/ExplorerEx/Database/SqlSugar/SugarContext.cs
@@ -1,23 +1,23 @@
using System;
-using System.Collections;
+using System.Collections.Generic;
using System.Collections.ObjectModel;
-using System.Collections.Specialized;
-using System.Diagnostics;
using System.IO;
using System.Linq;
+using System.Linq.Expressions;
using System.Reflection;
using System.Threading.Tasks;
using ExplorerEx.Database.Interface;
using ExplorerEx.Database.Shared;
+using ExplorerEx.Model;
using SqlSugar;
namespace ExplorerEx.Database.SqlSugar;
-public abstract class SugarContext : IDatabase {
+public class SugarContext : IDatabase, IDbContext where T : class, new() {
protected readonly SqlSugarClient ConnectionClient;
- protected SugarContext(string databaseFilename) {
- var path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, "SqlSugar");
+ public SugarContext(string databaseFilename) {
+ var path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, "Data");
if (!Directory.Exists(path)) {
Directory.CreateDirectory(path);
}
@@ -70,25 +70,89 @@ protected SugarContext(string databaseFilename) {
}
});
// 实体创建的时候执行
- ConnectionClient.Aop.DataExecuting = (value, info) => {
- var column = info.EntityColumnInfo;
- if (column.Navigat != null) {
- if (info.EntityValue is INotifyCollectionChanged ncc) {
-
- }
+ ConnectionClient.Aop.DataExecuting = (_, info) => Aop(info.EntityValue, info.EntityColumnInfo);
+ ConnectionClient.Aop.DataExecuted = (_, info) => {
+ foreach (var column in info.EntityColumnInfos) {
+ Aop(info.EntityValue, column);
}
};
}
- public virtual Task LoadAsync() {
- throw new InvalidOperationException();
+ private void Aop(object entityValue, EntityColumnInfo column) {
+ // TODO: Fuck this, I'm out
+ if (column.Navigat != null) {
+ switch (column.Navigat.NavigatType) {
+ case NavigateType.OneToOne:
+ if (column.UnderType == typeof(BookmarkCategory)) {
+ var category = ConnectionClient.Queryable().First(c => c.Name == ((BookmarkItem)entityValue).Name);
+ column.PropertyInfo.SetValue(entityValue, category);
+ }
+ break;
+ case NavigateType.OneToMany: // 这里是一个集合,那么就需要查询一次,填充集合
+ if (column.UnderType == typeof(ObservableCollection)) {
+ var list = ConnectionClient.Queryable()
+ .Where(i => i.CategoryForeignKey == ((BookmarkCategory)entityValue).Name)
+ .ToList();
+ column.PropertyInfo.SetValue(entityValue, new ObservableCollection(list));
+ }
+ break;
+ }
+ }
}
- public virtual void Save() {
- throw new InvalidOperationException();
+ public virtual Task LoadAsync() => Task.Run(() => {
+ ConnectionClient.DbMaintenance.CreateDatabase();
+ ConnectionClient.CodeFirst.InitTables();
+ });
+
+ public virtual void Save() => ConnectionClient.SaveQueues();
+
+ public virtual Task SaveAsync() => ConnectionClient.SaveQueuesAsync();
+
+ public virtual void Add(T item) => ConnectionClient.Insertable(item);
+
+ public virtual T? FirstOrDefault(Expression> match) => ConnectionClient.Queryable().First(match);
+
+ public virtual void Remove(T item) => ConnectionClient.Deleteable(item);
+
+ public virtual bool Contains(T item) => ConnectionClient.Queryable().Any(i => i == item);
+
+ public virtual bool Any(Expression> match) => ConnectionClient.Queryable().Any(match);
+
+ public virtual int Count() => ConnectionClient.Queryable().Count();
+}
+
+public class CachedSugarContext : SugarContext where T : class, new() {
+ private readonly SugarCache cache;
+
+ public CachedSugarContext(string databaseFilename) : base(databaseFilename) {
+ cache = new SugarCache(ConnectionClient);
+ }
+
+ public override async Task LoadAsync() {
+ await base.LoadAsync();
+ await Task.Run(cache.LoadDatabase);
}
- public virtual Task SaveAsync() {
- throw new InvalidOperationException();
+ public override void Save() => cache.Save();
+
+ public override Task SaveAsync() => Task.Run(cache.Save); // TODO: Thread safe???
+
+ public override void Add(T item) => cache.Add(item);
+
+ public override T? FirstOrDefault(Expression> match) => cache.FirstOrDefault(match.Compile());
+
+ public override void Remove(T item) => cache.Remove(item);
+
+ public override bool Contains(T item) => cache.Contains(item);
+
+ public override bool Any(Expression> match) => cache.Any(match.Compile());
+
+ public override int Count() => cache.Count();
+
+ public ObservableCollection GetBindable() {
+ var list = new List(cache.Count()); // 初始化容量
+ cache.ForEach(i => list.Add(i)); // 先使用List,这样Add的时候不会触发事件,减少消耗
+ return new ObservableCollection(list);
}
}
\ No newline at end of file
diff --git a/ExplorerEx/Model/FileListViewItem/Bookmark.cs b/ExplorerEx/Model/FileListViewItem/Bookmark.cs
index d4a8342..931174c 100644
--- a/ExplorerEx/Model/FileListViewItem/Bookmark.cs
+++ b/ExplorerEx/Model/FileListViewItem/Bookmark.cs
@@ -1,21 +1,11 @@
-// #define EFCore
-
-using System;
-using System.Collections.Generic;
+using System;
using System.Collections.ObjectModel;
-using System.Collections.Specialized;
using System.IO;
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Windows;
using System.Windows.Media;
using ExplorerEx.Converter;
-using ExplorerEx.Database.Interface;
using ExplorerEx.Database.Shared;
using ExplorerEx.Utils;
-using Microsoft.EntityFrameworkCore;
using static ExplorerEx.Utils.IconHelper;
-using Task = System.Threading.Tasks.Task;
namespace ExplorerEx.Model;
@@ -26,7 +16,7 @@ namespace ExplorerEx.Model;
[DbTable(TableName = "BookmarkCategoryDbSet")]
public class BookmarkCategory : NotifyPropertyChangedBase {
[DbColumn(IsPrimaryKey = true)]
- public string Name { get; set; } = null!;
+ public virtual string Name { get; set; } = null!;
///
/// 在Binding里使用
@@ -56,7 +46,7 @@ public BookmarkCategory(string name) {
}
public void AddBookmark(BookmarkItem item) {
- Children = new ObservableCollection();
+ Children ??= new ObservableCollection();
Children.Add(item);
OnPropertyChanged(nameof(Children));
OnPropertyChanged(nameof(Icon));
@@ -75,6 +65,9 @@ public override string ToString() {
public class BookmarkItem : FileListViewItem, IFilterable {
public override string DisplayText => Name;
+ ///
+ /// 不要设置这个的值
+ ///
[DbColumn]
public virtual string CategoryForeignKey { get; set; } = null!;
@@ -84,12 +77,13 @@ public class BookmarkItem : FileListViewItem, IFilterable {
[DbColumn(nameof(CategoryForeignKey), DbNavigateType.OneToOne)]
public virtual BookmarkCategory Category { get; set; } = null!;
- public BookmarkItem() : base(null!, null!, false) { }
+ public BookmarkItem() { }
- public BookmarkItem(string fullPath, string name, BookmarkCategory category) : base(null!, null!, false) {
+ public BookmarkItem(string fullPath, string name, BookmarkCategory category) {
FullPath = Path.GetFullPath(fullPath);
Name = name;
Category = category;
+ CategoryForeignKey = category.Name; // 不管了先设置上
category.AddBookmark(this);
}
@@ -123,138 +117,4 @@ protected override bool InternalRename(string newName) {
public bool Filter(string filter) {
return Name.ToLower().Contains(filter);
}
-}
-
-
-//public static class BookmarkManager {
-// public static DbCollection BookmarkCategories { get; }
-// public static DbCollection BookmarkItems { get; }
-
-// private static readonly IDatabase Database;
-
-// public static Task LoadDataBase() {
-// return Database.LoadAsync();
-// }
-
-// #region EF Core
-
-// static BookmarkManager() {
-// var dbContext = new EfCoreBookmarksDbContext();
-// Database = dbContext;
-// BookmarkCategories = new EfCoreDbCollection(Database, dbContext.BookmarkCategoryDbSet);
-// BookmarkItems = new EfCoreDbCollection(Database, dbContext.BookmarkDbSet);
-// }
-
-// ///
-// /// 对接到ef core
-// ///
-// ///
-// public class EfCoreDbCollection : DbCollection where TEntity : class {
-// private readonly DbSet dbSet;
-
-// public EfCoreDbCollection(IDatabase database, DbSet dbSet) : base(database) {
-// this.dbSet = dbSet;
-// }
-
-// private void DbSet_OnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) {
-// if (e.Action is not NotifyCollectionChangedAction.Replace and not NotifyCollectionChangedAction.Move) {
-// OnPropertyChanged(nameof(Count));
-// }
-// OnCollectionChanged(e);
-// }
-
-// public override void Add(TEntity item) {
-// dbSet.Local.Add(item);
-// }
-
-// public override void Clear() {
-// dbSet.Local.Clear();
-// }
-
-// public override bool Contains(TEntity item) {
-// return dbSet.Local.Contains(item);
-// }
-
-// public override void CopyTo(TEntity[] array, int arrayIndex) {
-// dbSet.Local.CopyTo(array, arrayIndex);
-// }
-
-// public override bool Remove(TEntity item) {
-// return dbSet.Local.Remove(item);
-// }
-
-// [MethodImpl(MethodImplOptions.AggressiveInlining)]
-// public override Task LoadAsync() {
-// dbSet.Local.ToObservableCollection().CollectionChanged += DbSet_OnCollectionChanged;
-// return dbSet.LoadAsync();
-// }
-
-// [MethodImpl(MethodImplOptions.AggressiveInlining)]
-// public override Task SaveChangesAsync() {
-// return database.SaveAsync();
-// }
-
-// public override IEnumerator GetEnumerator() {
-// return dbSet.Local.GetEnumerator();
-// }
-
-// public override int Count => dbSet.Local.Count;
-
-// public override bool IsReadOnly => false;
-// }
-
-// private class EfCoreBookmarksDbContext : DbContext, IDatabase {
-// public DbSet BookmarkCategoryDbSet { get; set; } = null!;
-// public DbSet BookmarkDbSet { get; set; } = null!;
-
-// private readonly string dbPath;
-
-// public EfCoreBookmarksDbContext() {
-// var path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, "Data");
-// if (!Directory.Exists(path)) {
-// Directory.CreateDirectory(path);
-// }
-// dbPath = Path.Combine(path, "BookMarks.db");
-// }
-
-// protected override void OnConfiguring(DbContextOptionsBuilder ob) {
-// ob.UseSqlite($"Data Source={dbPath}");
-// }
-
-// protected override void OnModelCreating(ModelBuilder modelBuilder) {
-// modelBuilder.Entity().HasOne(b => b.Category)
-// .WithMany(cb => cb.Children).HasForeignKey(b => b.CategoryForeignKey);
-// }
-
-// public async Task LoadAsync() {
-// try {
-// await Database.EnsureCreatedAsync();
-// await BookmarkCategoryDbSet.LoadAsync();
-// await BookmarkDbSet.LoadAsync();
-// if (BookmarkCategories.Count == 0) {
-// var defaultCategory = new BookmarkCategory("DefaultBookmark".L());
-// BookmarkCategories.Add(defaultCategory);
-// BookmarkItems.Add(new BookmarkItem(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Documents".L(), defaultCategory));
-// BookmarkItems.Add(new BookmarkItem(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Desktop".L(), defaultCategory));
-// await BookmarkCategories.SaveChangesAsync();
-// await BookmarkItems.SaveChangesAsync();
-// }
-// } catch (Exception e) {
-// MessageBox.Show("无法加载数据库,可能是权限不够或者数据库版本过旧,请删除Data文件夹后再试一次。\n错误为:" + e.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
-// Logger.Exception(e, false);
-// }
-// }
-
-// public void Save() {
-// throw new NotImplementedException();
-// }
-
-// [MethodImpl(MethodImplOptions.AggressiveInlining)]
-// public Task SaveAsync() {
-// return ((DbContext)this).SaveChangesAsync();
-// }
-// }
-
-
-// #endregion
-//}
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/ExplorerEx/Model/FileListViewItem/FileListViewItem.cs b/ExplorerEx/Model/FileListViewItem/FileListViewItem.cs
index 4584ec9..630cdcd 100644
--- a/ExplorerEx/Model/FileListViewItem/FileListViewItem.cs
+++ b/ExplorerEx/Model/FileListViewItem/FileListViewItem.cs
@@ -19,6 +19,8 @@ namespace ExplorerEx.Model;
/// 所有可以显示在中的项目的基类
///
public abstract class FileListViewItem : INotifyPropertyChanged {
+ protected FileListViewItem() { }
+
protected FileListViewItem(string fullPath, string name, bool isFolder) {
FullPath = fullPath;
Name = name;
@@ -70,7 +72,7 @@ public double Opacity {
private double opacity = 1d;
[DbColumn(IsPrimaryKey = true)]
- public string FullPath { get; protected init; }
+ public virtual string FullPath { get; protected init; }
public abstract string DisplayText { get; }
@@ -124,10 +126,7 @@ public bool IsSelected {
/// 加载文件的各项属性
///
public abstract void LoadAttributes(LoadDetailsOptions options);
-
- ///
- /// LoadIcon用到了shell,那并不是一个可以多线程的方法,所以与其每次都Task.Run,不如提高粗粒度
- ///
+
public abstract void LoadIcon(LoadDetailsOptions options);
#region 文件重命名
diff --git a/ExplorerEx/Model/FileListViewItem/FileSystemItem.cs b/ExplorerEx/Model/FileListViewItem/FileSystemItem.cs
index d9236c9..f3489e1 100644
--- a/ExplorerEx/Model/FileListViewItem/FileSystemItem.cs
+++ b/ExplorerEx/Model/FileListViewItem/FileSystemItem.cs
@@ -119,6 +119,7 @@ public override void LoadAttributes(LoadDetailsOptions options) {
if (FileSystemInfo == null) {
return;
}
+ FileSystemInfo.Refresh();
var type = FileUtils.GetFileTypeDescription(FileSystemInfo.Extension);
if (string.IsNullOrEmpty(type)) {
Type = "UnknownType".L();
@@ -215,13 +216,17 @@ protected static ImageSource InitializeIsEmptyFolder(string fullPath) {
public override string DisplayText => Name;
public override void LoadAttributes(LoadDetailsOptions options) {
+ if (FileSystemInfo == null) {
+ return;
+ }
isEmptyFolder = FolderUtils.IsEmptyFolder(FullPath);
IsEmptyFolderDictionary.Add(FullPath, isEmptyFolder);
Type = isEmptyFolder ? "EmptyFolder".L() : "Folder".L();
- var directoryInfo = new DirectoryInfo(FullPath);
+ var directoryInfo = (DirectoryInfo)FileSystemInfo;
+ directoryInfo.Refresh();
DateModified = directoryInfo.LastWriteTime;
DateCreated = directoryInfo.CreationTime;
- if (FileSystemInfo != null && FileSystemInfo.Attributes.HasFlag(FileAttributes.Hidden)) {
+ if (directoryInfo.Attributes.HasFlag(FileAttributes.Hidden)) {
Opacity = 0.5d;
}
}
diff --git a/ExplorerEx/Model/FileListViewItem/FolderOnlyItem.cs b/ExplorerEx/Model/FileListViewItem/FolderOnlyItem.cs
index 81dd675..4c11ffe 100644
--- a/ExplorerEx/Model/FileListViewItem/FolderOnlyItem.cs
+++ b/ExplorerEx/Model/FileListViewItem/FolderOnlyItem.cs
@@ -27,10 +27,19 @@ internal sealed class FolderOnlyItem : FileListViewItem {
/// 充当占位项目,以便展开
///
public static readonly FolderOnlyItem DefaultItem = new(Home) {
+ Name = "Loading".L()
+ };
+
+ ///
+ /// 充当占位项目,以便展开
+ ///
+ public static readonly FolderOnlyItem EmptyItem = new(Home) {
Name = "EmptyFolder".L()
};
- private static readonly ReadOnlyCollection DefaultChildren = new(new List { DefaultItem });
+ private static readonly ReadOnlyCollection LoadingChildren = new(new List { DefaultItem });
+
+ private static readonly ReadOnlyCollection EmptyChildren = new(new List { EmptyItem });
public override string DisplayText => Name;
@@ -89,7 +98,8 @@ public FolderOnlyItem(string zipPath, string relativePath, FolderOnlyItem parent
public FolderOnlyItem(DirectoryInfo directoryInfo, FolderOnlyItem parent) : base(directoryInfo.FullName, directoryInfo.Name, true) {
Parent = parent;
IsFolder = true;
- if (Directory.EnumerateDirectories(FullPath).Any()) {
+ // 只看有没有文件夹,不能用FolderUtils.IsEmptyFolder
+ if (Directory.EnumerateDirectories(FullPath).Any() || Directory.EnumerateFiles(FullPath, "*.zip").Any()) {
InitializeChildren();
}
}
@@ -104,7 +114,7 @@ public FolderOnlyItem(DriveInfo driveInfo): base(driveInfo.Name, DriveUtils.GetF
}
private void InitializeChildren() {
- Children = DefaultChildren;
+ Children = LoadingChildren;
actualChildren = new ConcurrentObservableCollection();
}
@@ -139,7 +149,7 @@ protected override bool InternalRename(string newName) {
public FolderOnlyItem Parent { get; }
///
- /// 枚举之前,先把这个设为,枚举完成后如数量大于1,设为
+ /// 枚举之前,先把这个设为,枚举完成后如数量大于1,设为
///
public IList? Children {
get => children;
@@ -173,7 +183,7 @@ public bool IsExpanded {
}
cts?.Cancel();
- Children = DefaultChildren;
+ Children = LoadingChildren;
if (actualChildren == null) {
actualChildren = new ConcurrentObservableCollection();
} else {
@@ -263,8 +273,12 @@ public bool IsExpanded {
}
item.LoadIcon(LoadDetailsOptions.Default);
}
+ } else {
+ Children = EmptyChildren;
}
}, token);
+ } else {
+ actualChildren?.Clear(); // 释放内存
}
}
}
@@ -285,7 +299,7 @@ public void UpdateDriveChildren() {
cts = new CancellationTokenSource();
var token = cts.Token;
Task.Run(() => {
- Children = DefaultChildren;
+ Children = LoadingChildren;
if (actualChildren == null) {
actualChildren = new ConcurrentObservableCollection();
} else {
diff --git a/ExplorerEx/Model/FileView.cs b/ExplorerEx/Model/FileView.cs
index b1094d5..733d85f 100644
--- a/ExplorerEx/Model/FileView.cs
+++ b/ExplorerEx/Model/FileView.cs
@@ -420,39 +420,6 @@ private void StageChange([CallerMemberName] string propertyName = null!) {
}
}
- ///
- /// 与另一个FileView对比,将差异暂存
- ///
- ///
- public void StageChangesFromOther(FileView other) {
- if (fullPath != other.fullPath) {
- StageChange(nameof(FullPath));
- }
- if (pathType != other.pathType) {
- StageChange(nameof(PathType));
- }
- if (sortBy != other.sortBy) {
- StageChange(nameof(SortBy));
- }
- if (isAscending != other.isAscending) {
- StageChange(nameof(IsAscending));
- }
- if (groupBy != other.groupBy) {
- StageChange(nameof(GroupBy));
- }
- if (fileViewType != other.fileViewType) {
- StageChange(nameof(FileViewType));
- }
- if (ItemSize != other.ItemSize) {
- StageChange(nameof(ItemSize));
- }
- if ((DetailListsData != null && other.DetailListsData == null) ||
- (DetailListsData == null && other.DetailListsData != null) ||
- (DetailListsData != null && other.DetailListsData != null && !DetailListsData.SequenceEqual(other.DetailListsData))) {
- StageChange(nameof(DetailListsData));
- }
- }
-
///
/// 将所有属性标记为已更改
///
diff --git a/ExplorerEx/Settings.cs b/ExplorerEx/Settings.cs
index 98095ef..8be16ec 100644
--- a/ExplorerEx/Settings.cs
+++ b/ExplorerEx/Settings.cs
@@ -2,11 +2,15 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
+using System.Globalization;
+using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Media;
+using System.Windows.Media.Imaging;
using System.Xml;
+using ExplorerEx.Command;
using ExplorerEx.Utils;
using Microsoft.Win32;
@@ -47,7 +51,7 @@ public SettingsExpander(string header, string? description, string? icon) : base
internal enum SettingsType {
Unknown,
Boolean,
- Integer,
+ Number,
String,
Select,
}
@@ -77,7 +81,7 @@ public object? Value {
OnPropertyChanged();
OnPropertyChanged(nameof(Self));
if (value != null) {
- ConfigHelper.Save(FullName, value);
+ ConfigHelper.SaveToBuffer(FullName, value);
} else {
ConfigHelper.Delete(FullName);
}
@@ -93,18 +97,22 @@ public object? Value {
///
public SettingsItem Self { get; }
- public object? Default { get; set; }
+ public virtual void SetDefaultValue(object? value) {
+ Value = value;
+ }
public bool GetBoolean() => Convert.ToBoolean(Value);
public int GetInt32() => Convert.ToInt32(Value);
- public string GetString() => Convert.ToString(Value) ?? Convert.ToString(Default) ?? string.Empty;
+ public double GetDouble() => Convert.ToDouble(Value);
+
+ public string GetString() => Convert.ToString(Value) ?? string.Empty;
///
/// 与不同,这个是专门用于监测值的变化
///
- public event Action