using HeBianGu.Base.WpfBase; using HeBianGu.Control.Explorer; using Hopetry.Services; using Minio.DataModel.Args; using Minio; using System; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using Microsoft.Extensions.Configuration; using Minio.ApiEndpoints; using System.Windows.Threading; using System.Drawing; using System.Windows.Media.Imaging; using System.Windows.Media; using System.Windows.Controls; using System.Collections.ObjectModel; using HeBianGu.App.Disk; using System.Windows.Controls.Primitives; using System.Diagnostics; using System.Windows.Input; using Microsoft.EntityFrameworkCore.Metadata.Internal; using System.Reflection; namespace Hopetry.Provider.Behaviors { public class ExplorerMinIOBehavior : Behavior { #region 依赖属性 public bool UseMinIO { get { return (bool)GetValue(UseMinIOProperty); } set { SetValue(UseMinIOProperty, value); } } public static readonly DependencyProperty UseMinIOProperty = DependencyProperty.Register("UseMinIO", typeof(bool), typeof(ExplorerMinIOBehavior), new PropertyMetadata(false, OnUseMinIOChanged)); //获取当前选中的文件 public IEnumerable GetSelectedItems() { var dataGrid = FindVisualChild(AssociatedObject); if (dataGrid != null) { return dataGrid.SelectedItems.Cast().ToList(); } return Enumerable.Empty(); } #endregion #region 字段和初始化 private IMinioClient _minioClient; private bool _isLocalHistoryRefresh; private bool _isNavigationCommand = false; protected override void OnAttached() { base.OnAttached(); InitializeMinIOClient(); // 监听路径变化 var pathDescriptor = DependencyPropertyDescriptor.FromProperty( Explorer.CurrentPathProperty, typeof(Explorer)); pathDescriptor.AddValueChanged(AssociatedObject, OnCurrentPathChanged); // 监听历史记录变化 var historyDescriptor = DependencyPropertyDescriptor.FromProperty( Explorer.HistoryProperty, typeof(Explorer)); historyDescriptor.AddValueChanged(AssociatedObject, OnHistoryChanged); // 初始加载MinIO内容 if (UseMinIO ) { Dispatcher.BeginInvoke((Action)(() => { RefreshMinIOPath(AssociatedObject.CurrentPath); }), DispatcherPriority.Loaded); } // 延迟执行以确保UI元素已加载 Dispatcher.BeginInvoke(new Action(() => { try { // 更安全的方式查找DataGrid var dataGrid = FindVisualChild(AssociatedObject); if (dataGrid != null) { dataGrid.CellEditEnding += DataGrid_CellEditEnding; } else { // 如果首次查找失败,可以尝试延迟再次查找 Dispatcher.BeginInvoke(new Action(() => { dataGrid = FindVisualChild(AssociatedObject); if (dataGrid != null) { dataGrid.CellEditEnding += DataGrid_CellEditEnding; } }), DispatcherPriority.Loaded); } } catch (Exception ex) { // 记录错误但不中断程序 System.Diagnostics.Debug.WriteLine($"附加CellEditEnding事件失败: {ex.Message}"); } }), DispatcherPriority.Loaded); var dataGrid = FindVisualChild(AssociatedObject); if (dataGrid != null) { dataGrid.BeginningEdit += DataGrid_BeginningEdit; } AssociatedObject.Loaded += OnExplorerLoaded; // 监听导航命令 CommandManager.AddPreviewExecutedHandler(AssociatedObject, OnPreviewCommandExecuted); } protected override void OnDetaching() { // Clean up event handlers var pathDescriptor = DependencyPropertyDescriptor.FromProperty( Explorer.CurrentPathProperty, typeof(Explorer)); pathDescriptor.RemoveValueChanged(AssociatedObject, OnCurrentPathChanged); var historyDescriptor = DependencyPropertyDescriptor.FromProperty( Explorer.HistoryProperty, typeof(Explorer)); historyDescriptor.RemoveValueChanged(AssociatedObject, OnHistoryChanged); var dataGrid = FindVisualChild(AssociatedObject); if (dataGrid != null) { dataGrid.CellEditEnding -= DataGrid_CellEditEnding; } CommandManager.RemovePreviewExecutedHandler(AssociatedObject, OnPreviewCommandExecuted); base.OnDetaching(); } #endregion #region 事件处理 private static void OnUseMinIOChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var behavior = (ExplorerMinIOBehavior)d; if ((bool)e.NewValue && behavior.AssociatedObject != null) { behavior.Dispatcher.BeginInvoke((Action)(() => { behavior.RefreshMinIOPath(behavior.AssociatedObject.CurrentPath); }), DispatcherPriority.ContextIdle); } } private void OnPreviewCommandExecuted(object sender, ExecutedRoutedEventArgs e) { if (e.Command == Explorer.Previous || e.Command == Explorer.Next) { _isNavigationCommand = true; Dispatcher.BeginInvoke(new Action(() => _isNavigationCommand = false), DispatcherPriority.ApplicationIdle); } } private void OnCurrentPathChanged(object sender, EventArgs e) { if (UseMinIO) { RefreshMinIOPath(AssociatedObject.CurrentPath); } } private void OnHistoryChanged(object sender, EventArgs e) { // 只有当历史记录变更不是由导航触发时才标记为本地刷新 _isLocalHistoryRefresh = true; } #endregion #region MinIO 操作 private void InitializeMinIOClient() { var builder = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("global.json", optional: false, reloadOnChange: true); // 构建配置 var config = builder.Build(); _minioClient = new MinioClient() .WithEndpoint(config["Minio:Endpoint"]) .WithCredentials(config["Minio:AccessKey"], config["Minio:SecretKey"]) .Build(); } public async void RefreshMinIOPath(string path,string searchText="") { if (AssociatedObject == null || _minioClient == null) return; try { AssociatedObject.IsEnabled = false; AssociatedObject.Cursor = System.Windows.Input.Cursors.Wait; var items = await GetMinIOItemsAsync(path, searchText); AssociatedObject.ItemsSource = items.ToObservable(); //var items = await GetMinIOItemsAsync(path); //AssociatedObject.ItemsSource = items.ToObservable(); // 2. 刷新导航栏 var navigationBar = FindVisualChild(AssociatedObject); if (navigationBar != null) { RefreshNavigationBar(navigationBar, path); } // Update history if this wasn't triggered by a history navigation if (!_isNavigationCommand && !string.IsNullOrEmpty(path)) { UpdateHistory(path); } _isLocalHistoryRefresh = false; } catch (Exception ex) { MessageBox.Show($"Error accessing MinIO: {ex.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error); } finally { AssociatedObject.IsEnabled = true; AssociatedObject.Cursor = null; } } private async Task> GetMinIOItemsAsync(string path,string searchText) { var items = new List(); if (string.IsNullOrEmpty(path)||path=="全部文件") { // List all buckets var buckets = await _minioClient.ListBucketsAsync(); items.AddRange(buckets.Buckets.Select(b => new MinIODirectoryModel(new MinIODirectoryInfo(b.Name, null, true, b.CreationDateDateTime)))); } else { // List objects in a bucket/path var parts = path.Split(new[] { '/' }, 2); var bucketName = parts[0]; var prefix = parts.Length > 1 ? parts[1] : null; var args = new ListObjectsArgs() .WithBucket(bucketName) .WithPrefix(prefix ?? "") .WithRecursive(false); var observable = _minioClient.ListObjectsEnumAsync(args); await foreach (var item in observable) { // 解码为正确的字符串 var decodedKey = Uri.UnescapeDataString(item.Key); if (item.IsDir) { items.Add(new MinIODirectoryModel( new MinIODirectoryInfo(bucketName, decodedKey, false, DateTime.Now))); } else { if (!string.IsNullOrEmpty(Path.GetFileName(decodedKey))) { string size = item.Size < 1024 * 1024 ? $"{Math.Ceiling((decimal)item.Size / 1024)}KB" : $"{Math.Ceiling((decimal)item.Size / (1024 * 1024))}MB"; items.Add(new MinIOFileModel(new MinIOFileInfo(bucketName, decodedKey, size, item.LastModifiedDateTime))); } } } } // 按修改时间降序排序(最新修改的排前面) return items.Where(x=>x.DisplayName.Contains(searchText)).OrderByDescending(x => { if (x is MinIOFileModel fileModel) { return ((MinIOFileInfo)fileModel.Model).LastModified; } return DateTime.Now; // 文件夹使用当前时间(或根据需求调整) }).ToList(); } //private void UpdateHistory(string path) //{ // if (string.IsNullOrEmpty(path)) // { // // 根路径时创建一个特殊的目录模型 // var rootItem = new DirectoryModel(new MinIODirectoryInfo("", "", true, DateTime.Now)) // { // DisplayName = RootDisplayName // }; // AssociatedObject.History.Insert(0, rootItem); // } // else // { // var parts = path.Split(new[] { '/' }, 2); // var bucketName = parts[0]; // var prefix = parts.Length > 1 ? parts[1] : null; // var dirInfo = new MinIODirectoryInfo(bucketName, prefix, false, DateTime.Now); // var historyItem = new DirectoryModel(dirInfo); // if (AssociatedObject.History.FirstOrDefault()?.Model?.FullName != path) // { // AssociatedObject.History.Insert(0, historyItem); // AssociatedObject.History = AssociatedObject.History // .Take(ExplorerSetting.Instance.HistCapacity) // .ToObservable(); // } // } // AssociatedObject.HistorySelectedItem = AssociatedObject.History.FirstOrDefault(); //} private void UpdateHistory(string path) { if (AssociatedObject == null || _isNavigationCommand) return; try { // 检查是否已经是历史记录中的第一个项目 var firstHistoryItem = AssociatedObject.History.FirstOrDefault(); if (firstHistoryItem?.Model?.FullName == path) return; // 创建适当的目录模型 DirectoryModel historyItem; if (string.IsNullOrEmpty(path) || path == RootDisplayName) { // 根路径时创建一个特殊的目录模型 historyItem = new DirectoryModel(new MinIODirectoryInfo("", "", true, DateTime.Now)) { DisplayName = RootDisplayName }; } else { var parts = path.Split(new[] { '/' }, 2); var bucketName = parts[0]; var prefix = parts.Length > 1 ? parts[1] : null; var dirInfo = new MinIODirectoryInfo(bucketName, prefix, false, DateTime.Now); historyItem = new DirectoryModel(dirInfo); } // 更新历史记录 _isLocalHistoryRefresh = true; // 防止递归触发 var newHistory = AssociatedObject.History.ToList(); newHistory.Insert(0, historyItem); // 限制历史记录数量 AssociatedObject.History = newHistory .Take(ExplorerSetting.Instance.HistCapacity) .ToObservable(); AssociatedObject.HistorySelectedItem = AssociatedObject.History.FirstOrDefault(); } catch (Exception ex) { Debug.WriteLine($"UpdateHistory error: {ex.Message}"); } finally { _isLocalHistoryRefresh = false; } } #endregion #region 图标处理 private static readonly Dictionary _iconCache = new Dictionary(); private const string DefaultFontFamily = "Segoe MDL2 Assets"; private const double DefaultIconSize = 16; public static System.Drawing.Icon GetIconForMinIOItem(string name, bool isDirectory, bool isBucket = false) { var cacheKey = $"{(isBucket ? "bucket" : (isDirectory ? "folder" : Path.GetExtension(name).ToLower()))}"; if (!_iconCache.TryGetValue(cacheKey, out var icon)) { icon = LoadMinIOIcon(name, isDirectory, isBucket); _iconCache[cacheKey] = icon; } return icon; } private static System.Drawing.Icon LoadMinIOIcon(string name, bool isDirectory, bool isBucket) { // 获取字体图标字符 string iconChar = GetFontIconChar(name, isDirectory, isBucket); // 创建字体图标ImageSource var imageSource = CreateFontIconImageSource(iconChar); // 转换为Icon return ConvertRenderTargetBitmapToIcon(imageSource as RenderTargetBitmap); } private static System.Drawing.Icon ConvertRenderTargetBitmapToIcon(RenderTargetBitmap renderTargetBitmap) { // 将 RenderTargetBitmap 转为 Bitmap var bitmap = new System.Drawing.Bitmap( renderTargetBitmap.PixelWidth, renderTargetBitmap.PixelHeight, System.Drawing.Imaging.PixelFormat.Format32bppPArgb); var data = bitmap.LockBits( new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppPArgb); renderTargetBitmap.CopyPixels( System.Windows.Int32Rect.Empty, data.Scan0, data.Height * data.Stride, data.Stride); bitmap.UnlockBits(data); // 从 Bitmap 创建 Icon var iconHandle = bitmap.GetHicon(); return System.Drawing.Icon.FromHandle(iconHandle); } private static string GetFontIconChar(string name, bool isDirectory, bool isBucket) { // 使用Segoe MDL2 Assets字体中的字符代码 if (isBucket) { return "\ue7c3"; // Cloud icon } if (isDirectory) { return "\ue8b7"; // Folder icon } // 按文件类型返回不同图标 string extension = Path.GetExtension(name)?.ToLower(); switch (extension) { case ".pdf": return "\uea90"; case ".jpg": case ".png": case ".jpeg": case ".gif": case ".bmp": case ".svg": return "\ueb9f"; // Picture icon case ".doc": case ".docx": return "\ue8a5"; // Word document icon case ".xls": case ".xlsx": return "\ue8a6"; // Excel document icon case ".ppt": case ".pptx": return "\ue8a7"; // PowerPoint icon case ".zip": case ".rar": case ".7z": return "\ue7b8"; // Zip folder icon case ".txt": case ".log": return "\ue8ab"; // Text document icon case ".mp3": case ".wav": case ".flac": return "\ue8d6"; // Audio icon case ".mp4": case ".avi": case ".mov": case ".wmv": return "\ue8b2"; // Video icon case ".exe": case ".msi": return "\ue756"; // Application icon case ".html": case ".htm": return "\ue842"; // HTML icon case ".cs": case ".cpp": case ".js": case ".java": return "\ue9a2"; // Code icon default: return "\ue7c4"; // Default document icon } } private static ImageSource CreateFontIconImageSource( string iconChar, string fontFamily = DefaultFontFamily, double fontSize = DefaultIconSize, System.Windows.Media.Brush foreground = null) { try { var textBlock = new System.Windows.Controls.TextBlock { Text = iconChar, FontFamily = new System.Windows.Media.FontFamily(fontFamily), FontSize = fontSize, Foreground = foreground ?? System.Windows.Media.Brushes.Black, HorizontalAlignment = System.Windows.HorizontalAlignment.Center, VerticalAlignment = System.Windows.VerticalAlignment.Center }; // 计算实际需要的尺寸 textBlock.Measure(new System.Windows.Size(double.PositiveInfinity, double.PositiveInfinity)); textBlock.Arrange(new System.Windows.Rect(textBlock.DesiredSize)); var renderTargetBitmap = new RenderTargetBitmap( (int)Math.Ceiling(textBlock.ActualWidth), (int)Math.Ceiling(textBlock.ActualHeight), 96, 96, PixelFormats.Pbgra32); renderTargetBitmap.Render(textBlock); renderTargetBitmap.Freeze(); return renderTargetBitmap; } catch { // 回退到默认图标 return CreateFontIconImageSource("\ue7c4", fontFamily, fontSize, foreground); } } #endregion #region 新建文件夹 private SystemInfoModel _newFolderItem; public void BeginEditNewFolder(SystemInfoModel newFolder) { if (AssociatedObject == null) { // 记录错误或尝试重新获取AssociatedObject Debug.WriteLine("Error: AssociatedObject is null in BeginEditNewFolder"); return; } // 获取当前绑定的集合 var itemsSource = AssociatedObject.ItemsSource as ObservableCollection; if (itemsSource == null) return; // 添加到集合最前面 itemsSource.Insert(0, newFolder); _newFolderItem = newFolder; // 使用Dispatcher确保在UI线程执行 AssociatedObject.Dispatcher.InvokeAsync(() => { // 查找DataGrid var dataGrid = FindVisualChild(AssociatedObject); if (dataGrid == null) { Debug.WriteLine("Error: Could not find DataGrid in Explorer"); return; } // 选中新创建的文件夹 dataGrid.SelectedItem = newFolder; // 开始编辑 dataGrid.Dispatcher.InvokeAsync(() => { // 强制更新布局 dataGrid.UpdateLayout(); // 滚动到视图并获取行 dataGrid.ScrollIntoView(newFolder); dataGrid.UpdateLayout(); // 再次更新布局确保行生成 var row = dataGrid.ItemContainerGenerator.ContainerFromItem(newFolder) as DataGridRow; if (row == null) { // 如果仍然为空,尝试遍历所有行 foreach (var item in dataGrid.Items) { dataGrid.ScrollIntoView(item); var tempRow = dataGrid.ItemContainerGenerator.ContainerFromItem(item) as DataGridRow; if (tempRow != null && tempRow.DataContext == newFolder) { row = tempRow; break; } } } if (row != null) { var cell = GetCell(dataGrid, row, 1); if (cell != null) { cell.Focus(); dataGrid.BeginEdit(); // 获取文本框并全选文本 var textBox = FindVisualChild(cell); if (textBox != null) { textBox.SelectAll(); } } } }, DispatcherPriority.Input); }, DispatcherPriority.Background); } private void DataGrid_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e) { if (_newFolderItem == null || e.Row.DataContext != _newFolderItem) return; if (e.EditAction == DataGridEditAction.Commit) { //var textBox = e.EditingElement as TextBox; // 使用递归查找TextBox var textBox = FindVisualChild(e.EditingElement); if (textBox != null) { var newName = textBox.Text.Trim(); if (!string.IsNullOrEmpty(newName)) { // 更新模型名称 _newFolderItem.DisplayName = newName; // 通知ViewModel在MinIO中创建文件夹 if (AssociatedObject.DataContext is LoyoutViewModel vm) { vm.CreateMinIOFolder(newName).ConfigureAwait(false); } } else { // 如果名称为空,移除该项 if (AssociatedObject.ItemsSource is ObservableCollection items) { items.Remove(_newFolderItem); } } } } else if (e.EditAction == DataGridEditAction.Cancel) { // 如果取消编辑,移除该项 if (AssociatedObject.ItemsSource is ObservableCollection items) { items.Remove(_newFolderItem); } } if (_newFolderItem is MinIODirectoryModel directoryModel) { directoryModel.IsRenaming = true; // 编辑完成后设为不可编辑 } _newFolderItem = null; } private DataGridCell GetCell(DataGrid dataGrid, DataGridRow row, int column) { if (row == null) return null; // 获取行的视觉子元素 - DataGridCellsPresenter var presenter = FindVisualChild(row); if (presenter == null) { // 如果行是虚拟化的,可能需要先滚动到视图 dataGrid.ScrollIntoView(row, dataGrid.Columns[column]); presenter = FindVisualChild(row); if (presenter == null) return null; } // 获取指定列的单元格 var cell = presenter.ItemContainerGenerator.ContainerFromIndex(column) as DataGridCell; if (cell == null) { // 如果单元格尚未生成,再次尝试滚动到视图 dataGrid.ScrollIntoView(row, dataGrid.Columns[column]); cell = presenter.ItemContainerGenerator.ContainerFromIndex(column) as DataGridCell; } return cell; } private static T FindVisualChild(DependencyObject parent) where T : DependencyObject { if (parent == null) return null; // 先检查parent本身是否是目标类型 if (parent is T result) { return result; } try { int childrenCount = VisualTreeHelper.GetChildrenCount(parent); for (int i = 0; i < childrenCount; i++) { var child = VisualTreeHelper.GetChild(parent, i); result = FindVisualChild(child); if (result != null) { return result; } } } catch (Exception ex) { Debug.WriteLine($"FindVisualChild error: {ex.Message}"); } return null; } private void DataGrid_BeginningEdit(object sender, DataGridBeginningEditEventArgs e) { if (e.Row.DataContext is MinIODirectoryModel directoryModel) { // 只有 IsRenaming 为 true 的文件夹可以编辑 e.Cancel = directoryModel.IsRenaming; } else { // 其他类型项目不可编辑 e.Cancel = true; } } #endregion #region 导航栏属性 // 添加导航栏控制属性 public string RootDisplayName { get { return (string)GetValue(RootDisplayNameProperty); } set { SetValue(RootDisplayNameProperty, value); } } public static readonly DependencyProperty RootDisplayNameProperty = DependencyProperty.Register("RootDisplayName", typeof(string), typeof(ExplorerMinIOBehavior), new PropertyMetadata("全部文件")); private void OnExplorerLoaded(object sender, RoutedEventArgs e) { var navigationBar = FindVisualChild(AssociatedObject); if (navigationBar != null) { // 替换导航栏的RefreshData方法 ReplaceNavigationBarRefreshMethod(navigationBar); // 强制刷新导航栏 RefreshNavigationBar(navigationBar, AssociatedObject.CurrentPath); } } private void ReplaceNavigationBarRefreshMethod(NavigationBar navigationBar) { // 获取原始RefreshData方法 var originalMethod = typeof(NavigationBar).GetMethod("RefreshData", BindingFlags.NonPublic | BindingFlags.Instance); if (originalMethod == null) return; // 动态创建委托替换原始方法 var methodDelegate = (Action)delegate (string path) { RefreshNavigationBar(navigationBar, path); }; // 使用反射替换方法(简化版,实际生产环境可能需要更安全的方式) var field = typeof(NavigationBar).GetField("_refreshData", BindingFlags.NonPublic | BindingFlags.Instance); field?.SetValue(navigationBar, methodDelegate); } private void RefreshNavigationBar(NavigationBar navigationBar, string path) { if (!UseMinIO) { // 本地文件系统模式,使用原始逻辑 var originalMethod = typeof(NavigationBar).GetMethod("OriginalRefreshData", BindingFlags.NonPublic | BindingFlags.Instance); originalMethod?.Invoke(navigationBar, new object[] { path }); return; } // MinIO模式下的自定义路径处理 List dirs = new List(); if (string.IsNullOrEmpty(path)||path=="全部文件") { // 根节点显示自定义名称 var root = ExplorerProxy.Instance.CreateDirectoryInfo(RootDisplayName); dirs.Add(root); } else { // 处理MinIO路径格式 bucketname/path/to/item var parts = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); string currentPath = ""; // 添加根节点 dirs.Add(ExplorerProxy.Instance.CreateDirectoryInfo(RootDisplayName)); // 添加各级路径 for (int i = 0; i < parts.Length; i++) { currentPath += (i > 0 ? "/" : "") + parts[i]; var dir = ExplorerProxy.Instance.CreateDirectoryInfo(currentPath); dirs.Add(dir); } } // 更新导航栏ItemsSource navigationBar.ItemsSource = dirs.Select(l => new DirectoryModel(l)); } #endregion #region 搜索行为实现 #endregion } #region MinIO 模型类 public interface IMinIOFileInfo : ISystemFileInfo { string BucketName { get; } bool IsDirectory { get; } bool IsBucket { get; } } public class MinIOFileInfo : IMinIOFileInfo, IFileInfo { public MinIOFileInfo(string bucketName, string key, string size, DateTime? lastModified) { BucketName = bucketName; FullName = $"{bucketName}/{key}"; Name = Path.GetFileName(key); Size = size; LastModified = lastModified; } public string BucketName { get; } public bool IsDirectory => false; public bool IsBucket => false; public string Name { get; } public string FullName { get; } public string Size { get; } public DateTime? LastModified { get; } public DateTime? LastWriteTime => LastModified; public FileAttributes Attributes => FileAttributes.Normal; } public class MinIODirectoryInfo : IMinIOFileInfo, IDirectoryInfo { public MinIODirectoryInfo(string bucketName, string key, bool isBucket, DateTime creationDate) { BucketName = bucketName; FullName = string.IsNullOrEmpty(key) ? bucketName : $"{bucketName}/{key}"; Name = string.IsNullOrEmpty(key) ? bucketName : key.TrimEnd('/').Split('/').Last(); IsBucket = isBucket; LastWriteTime = creationDate; } public string BucketName { get; } public bool IsDirectory => true; public bool IsBucket { get; } public string Name { get; } public string FullName { get; } public DateTime LastWriteTime { get; } public FileAttributes Attributes => FileAttributes.Directory; } public class MinIOFileModel : FileModel { public MinIOFileModel(IFileInfo model) : base(model) { this.Icon = "\ue7c4"; // 默认文件图标 } public new Icon Logo => ExplorerMinIOBehavior.GetIconForMinIOItem( this.Model.Name, isDirectory: false); private bool _isRenaming = true; // 默认不可编辑 public bool IsRenaming { get => _isRenaming; set { if (_isRenaming != value) { _isRenaming = value; RaisePropertyChanged(nameof(IsRenaming)); } } } private bool _isChecked = false; // 默认不选中 public new bool IsChecked { get => _isChecked; set { if (_isChecked != value) { _isChecked = value; RaisePropertyChanged(nameof(IsChecked)); } } } } public class MinIODirectoryModel : DirectoryModel { public MinIODirectoryModel(IDirectoryInfo model) : base(model) { this.Icon = "\ue8b7"; // 默认文件夹图标 } public new Icon Logo => ExplorerMinIOBehavior.GetIconForMinIOItem( this.Model.Name, isDirectory: true, isBucket: (this.Model as IMinIOFileInfo)?.IsBucket ?? false); private bool _isRenaming = true; // 默认不可编辑 public bool IsRenaming { get => _isRenaming; set { if (_isRenaming != value) { _isRenaming = value; RaisePropertyChanged(nameof(IsRenaming)); } } } private bool _isChecked = false; // 默认不选中 public new bool IsChecked { get => _isChecked; set { if (_isChecked != value) { _isChecked = value; RaisePropertyChanged(nameof(IsChecked)); } } } } #endregion }