添加文件项类,优化模块页面功能,修复菜单项启用状态

This commit is contained in:
muqing 2025-01-16 14:27:07 +08:00
parent e3b741f07d
commit e7be2802a3
8 changed files with 291 additions and 355 deletions

View File

@ -1,101 +1,64 @@
using System.Collections.ObjectModel;
using System.Diagnostics;
namespace RustTools.Editor;
public class EditorLoad
{
/// <summary>
/// 加载所有的文件 Debug 用
/// 获取目录下的文件和文件夹
/// </summary>
/// <param name="directoryInfo"></param>
/// <param name="parentItem"></param>
private void LoadDirectory(DirectoryInfo directoryInfo, ExplorerItem parentItem)
/// <param name="dir"></param>
/// <returns></returns>
public static ObservableCollection<FileItem> GetData(string dir)
{
// 获取当前目录中的所有子目录
var directories = directoryInfo.GetDirectories();
foreach (var directory in directories)
{
// 创建新的 ExplorerItem 代表当前子目录
var folderItem = new ExplorerItem
{
Name = directory.Name,
Type = ExplorerItem.ExplorerItemType.Folder
};
// 将这个目录项添加到父级的 Children 集合中
parentItem.Children.Add(folderItem);
// 递归调用,继续加载子目录中的内容
LoadDirectory(directory, folderItem);
}
// 获取当前目录中的所有文件
var files = directoryInfo.GetFiles();
foreach (var file in files)
{
// 创建新的 ExplorerItem 代表当前文件
var fileItem = new ExplorerItem
{
Name = file.Name,
Type = ExplorerItem.ExplorerItemType.File
};
// 将这个文件项添加到父级的 Children 集合中
parentItem.Children.Add(fileItem);
}
}
public ObservableCollection<ExplorerItem> GetData(string dir)
{
var list = new ObservableCollection<ExplorerItem>();
var list = new ObservableCollection<FileItem>();
var directoryInfos = new DirectoryInfo(dir);
// 创建根节点 ExplorerItem 根节点不显示防止用户删除
//var rootItem = new ExplorerItem
//{
// Name = directoryInfos.Name,
// Dir = directoryInfos.FullName,
// Type = ExplorerItem.ExplorerItemType.Folder,
//};
//LoadDirectory(directoryInfos,rootItem);
//获取文件夹
foreach (var file in directoryInfos.GetDirectories())
{
var explorerItem = new ExplorerItem()
var explorerItem = new FileItem(true)
{
Name = file.Name,
Dir = file.FullName,
Type = ExplorerItem.ExplorerItemType.Folder
};
//检测是否有子文件
if (HasChildren(file.FullName))
{
explorerItem.Children.Add(new FileItem());
}
list.Add(explorerItem);
foreach (var a in file.GetDirectories())
{
explorerItem.Children.Add(new ExplorerItem()
{
Name = a.Name,
Dir = a.FullName,
Type = ExplorerItem.ExplorerItemType.Folder
});
}
foreach (var a in file.GetFiles())
{
explorerItem.Children.Add(new ExplorerItem()
{
Name = a.Name,
Dir = a.FullName,
Type = ExplorerItem.ExplorerItemType.File
});
}
}
//获取文件
foreach (var file in directoryInfos.GetFiles())
{
list.Add(new ExplorerItem()
list.Add(new FileItem()
{
Name = file.Name,
Dir = file.FullName,
Type = ExplorerItem.ExplorerItemType.File
IsFolder = false,
});
}
return list;
}
private static bool HasChildren(string path)
{
try
{
// 检查是否有子目录或子文件
return Directory.EnumerateDirectories(path).Any() || Directory.EnumerateFiles(path).Any();
}
catch (UnauthorizedAccessException)
{
// 捕获权限异常(例如无法访问某些系统文件夹)
return false;
}
catch (Exception ex)
{
Debug.WriteLine($"Error checking children for path {path}: {ex.Message}");
return false;
}
}
}

View File

@ -1,140 +1,108 @@

using System.Diagnostics;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Input;
using RustTools.muqing;
using Windows.ApplicationModel.DataTransfer;
using Windows.Storage;
namespace RustTools.Editor;
public class EditorTreeView : TreeView
{
public EditorTreeView()
{
//CanDragItems = false;
//CanReorderItems =false;
//DragEnter += EditorTreeView_DragEnter;
DragItemsStarting += TreeView_DragItemsStarting;
DragItemsCompleted += EditorTreeView_DragItemsCompleted;
//DragOver += TreeView_DragOver;
//Drop += TreeView_Drop;
// 在构造函数中注册事件处理程序
}
private void TreeView_DragItemsStarting(TreeView sender, TreeViewDragItemsStartingEventArgs e)
{
//gj.sc("TreeView_DragItemsStarting"+e);
var items = e.Items.Cast<ExplorerItem>().ToList();
var firstItem = items.First();
gj.sc(firstItem.Dir);
e.Data.SetData("path", firstItem.Dir);
e.Data.RequestedOperation = DataPackageOperation.Move; // Use Copy to avoid moving items
}
private void EditorTreeView_DragItemsCompleted(TreeView sender, TreeViewDragItemsCompletedEventArgs e)
{
//点击事件
this.ItemInvoked += TreeView_ItemInvoked;
// TreeView.Expanding
//当用户点击小箭头展开节点时触发。
// 获取拖拽的项
var items = e.Items.Cast<ExplorerItem>().ToList();
//TreeView.Collapsed
//当用户点击小箭头折叠节点时触发。
this.Expanding += TreeView_Expanding;
this.Collapsed += TreeView_Collapsed;
}
private async void TreeView_ItemInvoked(TreeView sender, TreeViewItemInvokedEventArgs args)
{
// 获取触发点击的 TreeViewItem
var treeViewItem = sender.ContainerFromItem(args.InvokedItem) as TreeViewItem;
// 检查是否有至少一个项被放下
if (items.Any())
{
var firstItem = items.First(); // 获取第一个放下的项
// 输出放下项的信息
Debug.WriteLine($"放下了 {firstItem.Dir}");
}
}
/// <summary>
/// 如果是shift则开启多选状态
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void treeView_KeyDown(object sender, KeyRoutedEventArgs e)
if (args.InvokedItem is FileItem invokedItem)
{
// 检查是否按下了Shift键
if (e.Key == Windows.System.VirtualKey.Shift)
if (invokedItem.IsFolder)
{
gj.sc(e.Key);
// 启用多选模式
SelectionMode = TreeViewSelectionMode.Multiple;
//invokedItem.Children.Clear();
//Debug.WriteLine($"Folder clicked: {invokedItem.Name}");
//// 异步加载子项数据
//var newChildren = await Task.Run(() => EditorLoad.GetData(invokedItem.Dir));
//// 更新 Children 集合
//foreach (var child in newChildren)
//{
// invokedItem.Children.Add(child);
//}
//// 展开 TreeViewItem
//if (treeViewItem != null&&treeViewItem.IsExpanded==false)
//{
// treeViewItem.IsExpanded = true;
//}
}
}
private void treeView_KeyUp(object sender, KeyRoutedEventArgs e)
else
{
// 检查是否松开了Shift键
if (e.Key == Windows.System.VirtualKey.Shift)
{ // 清除当前多选模式下选中的项目
var selectedItems = SelectedItems.ToList();
foreach (var item in selectedItems)
{
SelectedItems.Remove(item);
Debug.WriteLine($"File clicked: {invokedItem.Name}");
}
gj.sc("取消");
// 取消多选模式
SelectionMode = TreeViewSelectionMode.Single;
//treeView.SelectedItems.Clear();
}
}
/// <summary>
/// 其他窗口的文件夹拖过来的例子
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void TreeView_DragOver(object sender, DragEventArgs e)
// TreeView.Expanding 事件
private async void TreeView_Expanding(TreeView sender, TreeViewExpandingEventArgs args)
{
gj.sc(e);
// Allow dragging but prevent reordering
if (e.DataView.Contains(StandardDataFormats.StorageItems))
if (args.Item is FileItem expandingItem)
{
e.AcceptedOperation = DataPackageOperation.Move; // Use Copy to avoid reordering
e.Handled = true;
Debug.WriteLine($"Expanding: {expandingItem.Name}");
// 如果需要动态加载子项(仅当没有加载过子项时)
if (expandingItem.IsFolder)
{
expandingItem.Children.Clear();
var newChildren = await Task.Run(() => EditorLoad.GetData(expandingItem.Dir));
// 更新 Children 集合
foreach (var child in newChildren)
{
expandingItem.Children.Add(child);
}
Debug.WriteLine($"Loaded children for: {expandingItem.Name}");
}
/// <summary>
/// 其他文件夹拖过来的放下事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void TreeView_Drop(object sender, DragEventArgs e)
{
gj.sc("TreeView_Drop: " + e);
// Handle drop event if needed but prevent reordering
if (e.DataView.Contains(StandardDataFormats.StorageItems))
{
var storageItems = await e.DataView.GetStorageItemsAsync();
// 获取目标文件夹,即拖放的位置
// 获取目标位置
var treeView = sender as TreeView;
var data = await e.DataView.GetDataAsync("path");
gj.sc(data);
foreach (var item in storageItems)
{
if (item is StorageFolder folder)
{
// 移动文件夹
gj.sc(folder.Path + "-->");
//var newFolder = await folder.MoveAsync(targetFolder, folder.Name, NameCollisionOption.ReplaceExisting);
}
else if (item is StorageFile file)
{
// 移动文件
//var newFile = await file.MoveAsync(targetFolder, file.Name, NameCollisionOption.ReplaceExisting);
}
}
e.Handled = true;
// TreeView.Collapsed 事件
private void TreeView_Collapsed(TreeView sender, TreeViewCollapsedEventArgs args)
{
if (args.Item is FileItem collapsedItem)
{
// 清空子节点集合
if (collapsedItem.IsFolder && collapsedItem.Children != null)
{
// 设置当前项的所有子节点的 IsExpanded 为 false
//SetIsExpandedForChildren(collapsedItem, false);
Debug.WriteLine($"Children cleared for: {collapsedItem.Name}");
}
// 处理折叠事件(例如,清理子项、节省资源等)
}
}
// 递归设置子节点的 IsExpanded 为 false
private void SetIsExpandedForChildren(FileItem item, bool isExpanded)
{
foreach (var child in item.Children)
{
// 设置每个子项的 IsExpanded 状态
child.IsExpanded = isExpanded;
// 如果子项有子节点,递归处理
if (child.IsFolder && child.Children.Count > 0)
{
SetIsExpandedForChildren(child, isExpanded);
}
}
}
}

View File

@ -6,6 +6,7 @@
xmlns:controlpages="using:RustTools.Editor"
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:editor="using:RustTools.Editor"
xmlns:local="using:RustTools"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:windowex="using:WinUIEx"
@ -15,19 +16,20 @@
<Page Name="page">
<Page.Resources>
<DataTemplate x:Key="FolderTemplate">
<!-- 这是文件夹 -->
<DataTemplate x:Key="FolderTemplate" x:DataType="editor:FileItem">
<TreeViewItem
AutomationProperties.Name="{Binding Name}"
IsExpanded="False"
ItemsSource="{Binding Children}">
AutomationProperties.Name="{x:Bind Name}"
IsExpanded="{x:Bind IsExpanded, Mode=TwoWay}"
ItemsSource="{x:Bind Children}">
<StackPanel Orientation="Horizontal">
<FontIcon Glyph="&#xE8B7;" />
<TextBlock Margin="0,0,10,0" />
<TextBlock Text="{Binding Name}" />
<TextBlock Text="{x:Bind Name}" />
</StackPanel>
</TreeViewItem>
</DataTemplate>
<!-- 这是文件 -->
<DataTemplate x:Key="FileTemplate">
<TreeViewItem AutomationProperties.Name="{Binding Name}" IsExpanded="False">
<StackPanel Orientation="Horizontal">
@ -78,13 +80,15 @@
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<!--
TreeView 绑定资源和拖放事件
CanReorderItems="True"
-->
<controlpages:EditorTreeView
Name="treeView"
DoubleTapped="treeView_DoubleTapped"
ItemInvoked="TreeView_ItemInvoked"
x:Name="treeView"
AllowDrop="True"
ItemTemplateSelector="{StaticResource ExplorerItemTemplateSelector}"
ItemsSource="{x:Bind DataSource}"
ScrollViewer.IsVerticalRailEnabled="False"
SelectionMode="Single" />
</ScrollViewer>
@ -107,7 +111,6 @@
Grid.Row="0"
Height="auto"
IsAddTabButtonVisible="False"
TabCloseRequested="TabView_TabCloseRequested"
TabItemsSource="{x:Bind TabViewList}" />
</Grid>

View File

@ -1,5 +1,5 @@
using System.Collections.ObjectModel;
using System.Diagnostics;
using Microsoft.UI;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
@ -14,8 +14,14 @@ public sealed partial class EditorWin : WindowEx
{
private readonly ObservableCollection<TabViewItem> TabViewList = new();
//Ŀ¼Áбí
public ObservableCollection<ExplorerItem> DataSource = new();
public EditorWin()
public ObservableCollection<FileItem> DataSource = new();
/// <summary>
/// 编辑器主窗口
/// 传入路径
/// </summary>
/// <param name="path"></param>
public EditorWin(string path)
{
InitializeComponent();
gj.SetBackTheme(this);
@ -26,16 +32,12 @@ public sealed partial class EditorWin : WindowEx
gj.UpdateTitleBar(this, frame.ActualTheme);
page.RequestedTheme = frame.ActualTheme;
}
//new CodeEditorControl();
//new Editor.
//WindowManager.Get(this).IsMinimizable = false;
//app = GetAppWindowForCurrentWindow();
//app.Closing += OnClosing;
//Closed += EditorWin_Closed;
var directoryInfo = new DirectoryInfo("D:\\steam\\steamapps\\common\\Rusted Warfare\\mods\\units\\赤道·联合进攻0.9补丁版0.2");
DataSource = new EditorLoad().GetData(directoryInfo.FullName);
//Debug.WriteLine(path);
var directoryInfo = new DirectoryInfo(path);
Title = directoryInfo.Name;
TitleText.Text = directoryInfo.Name;
DataSource = EditorLoad.GetData(directoryInfo.FullName);
treeView.ItemsSource = DataSource;
Closed += EditorWin_Closed;
}
@ -83,86 +85,7 @@ public sealed partial class EditorWin : WindowEx
ClosedDialog = null;
}
private Microsoft.UI.Windowing.AppWindow GetAppWindowForCurrentWindow()
{
var hWnd = WindowNative.GetWindowHandle(this);
var myWndId = Win32Interop.GetWindowIdFromWindow(hWnd);
return Microsoft.UI.Windowing.AppWindow.GetFromWindowId(myWndId);
}
/// <summary>
/// 选中事件
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
private void TreeView_ItemInvoked(TreeView sender, TreeViewItemInvokedEventArgs e)
{
// 获取当前选中的项
// 获取被点击的项
var invokedItem = e.InvokedItem;
// 检查是否重复选择
if (sender.SelectedItem is ExplorerItem selectedItem && invokedItem != null && selectedItem == invokedItem)
{
// 如果是同一个项,直接返回,不进行进一步处理
return;
}
if (invokedItem is not ExplorerItem explorerItem)
{
return;
}
if (explorerItem.Type == ExplorerItem.ExplorerItemType.Folder)
{
var directoryInfo = new DirectoryInfo(explorerItem.Dir);
}
}
private void TabView_TabCloseRequested(TabView sender, TabViewTabCloseRequestedEventArgs args)
{
TabViewList.Remove(args.Tab);
}
/// <summary>
/// 双击事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void treeView_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
{
gj.sc(e.OriginalSource);
var treeViewItem = e.OriginalSource as Grid;
if (treeViewItem == null) { return; }
if (treeViewItem.DataContext is not ExplorerItem explorerItem) { return; }
if (explorerItem.Type == ExplorerItem.ExplorerItemType.File)
{
// 查找特定的 TabViewItem
var tabViewItemToFind = TabViewList.FirstOrDefault(item => (item as TabViewItem)?.Tag.ToString() == explorerItem.Dir) as TabViewItem;
// 获取 TabViewItem 的索引位置
if (tabViewItemToFind != null)
{
tabview.SelectedIndex = TabViewList.IndexOf(tabViewItemToFind);
return;
}
var fileInfo = new FileInfo(explorerItem.Dir);
//var name = Path.GetFileNameWithoutExtension(fileInfo.FullName);
var newItem = new TabViewItem()
{
Tag = explorerItem.Dir,
// 获取文件名,不包含扩展名
Header = fileInfo.Name,
IconSource = new Microsoft.UI.Xaml.Controls.SymbolIconSource() { Symbol = Symbol.Document }
};
//if(tabview.TabItems.)
var v = wj.dqwb(explorerItem.Dir);
var textControlBox = new RichEditBox();
//textControlBox.Height = Height;
textControlBox.Document.SetText(Microsoft.UI.Text.TextSetOptions.None, v);
newItem.Content = textControlBox;
TabViewList.Insert(0, newItem);
tabview.SelectedIndex = 0;
}
}
}

View File

@ -1,74 +1,30 @@
using System.Collections.ObjectModel;
using System.ComponentModel;

using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
namespace RustTools.Editor;
public class ExplorerItemTemplateSelector : DataTemplateSelector
{
public DataTemplate FolderTemplate
public DataTemplate? FolderTemplate
{
get; set;
}
public DataTemplate FileTemplate
public DataTemplate? FileTemplate
{
get; set;
}
protected override DataTemplate SelectTemplateCore(object item)
{
var explorerItem = (ExplorerItem)item;
return explorerItem.Type == ExplorerItem.ExplorerItemType.Folder ? FolderTemplate : FileTemplate;
}
}
public class ExplorerItem : INotifyPropertyChanged
if (((FileItem)item).IsFolder)
{
public enum ExplorerItemType { Folder, File };
public event PropertyChangedEventHandler PropertyChanged;
public string? Name
return FolderTemplate;
}
else
{
get; set;
return FileTemplate;
}
public ExplorerItemType Type
{
get; set;
}
public string? Dir
{
get; set;
}
private ObservableCollection<ExplorerItem>? m_children;
public ObservableCollection<ExplorerItem> Children
{
get
{
m_children ??= new ObservableCollection<ExplorerItem>();
return m_children;
}
set => m_children = value;
}
private bool m_isExpanded;
public bool IsExpanded
{
get => m_isExpanded;
set
{
if (m_isExpanded != value)
{
m_isExpanded = value;
NotifyPropertyChanged(nameof(IsExpanded));
}
}
}
private void NotifyPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public static implicit operator ExplorerItem(bool v)
{
throw new NotImplementedException();
//return base.SelectTemplateCore(item);
}
}

View File

@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace RustTools.Editor;
public class FileItem
{
public string Name
{
get; set;
}
public string Dir
{
get; set;
}
public bool IsFolder
{
get; set;
}
public bool IsExpanded
{
get; set;
} = false; // 用来控制展开状态
public ObservableCollection<FileItem> Children
{
get; set;
}
public FileItem()
{
}
public FileItem(bool isFolder)
{
IsFolder = isFolder;
if (isFolder)
{
Children = new ObservableCollection<FileItem>();
}
}
}
//public class FileItem : INotifyPropertyChanged
//{
// private string _name;
// public string Name
// {
// get => _name;
// set
// {
// _name = value;
// OnPropertyChanged();
// }
// }
// public string Dir
// {
// get; set;
// }
// public bool IsFolder
// {
// get; set;
// }
// public ObservableCollection<FileItem> Children
// {
// get; set;
// }
// public bool IsExpanded
// {
// get; set;
// } = false; // 用来控制展开状态
// public event PropertyChangedEventHandler PropertyChanged;
// public FileItem()
// {
// }
// public FileItem(bool isFolder)
// {
// IsFolder = isFolder;
// if (isFolder)
// {
// Children = new ObservableCollection<FileItem>();
// }
// }
// protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
// {
// PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
// }
//}

View File

@ -53,7 +53,8 @@
<Grid.ContextFlyout>
<MenuFlyout>
<MenuFlyoutItem
IsEnabled="False"
Click="Button_OpenMod"
IsEnabled="True"
Text="打开"
ToolTipService.ToolTip="制作中···" />
<MenuFlyoutItem Click="Button_Rwmod" Text="打包" />

View File

@ -269,7 +269,8 @@ public sealed partial class ModulePage : Page
{
// 在这里处理双击项
var IsRwmod = clickedItem.IsRwmod; // 假设你的项有一个 Name 属性
if (IsRwmod) {
if (IsRwmod)
{
UnzipRwmod(clickedItem);
}
@ -319,7 +320,29 @@ public sealed partial class ModulePage : Page
/// <param name="e"></param>
private void Button_OpenDir(object sender, RoutedEventArgs e)
{
wj.OpenFileExplorer(ViewModel.ListMod[0].Dri);
var view = sender as MenuFlyoutItem;
// 替换为实际的数据类型
if (view?.DataContext is DataObject clickedItem)
{
wj.OpenFileExplorer(clickedItem.Dri);
}
}
/// <summary>
/// 打开模组_文件夹
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Button_OpenMod(object sender, RoutedEventArgs e)
{
var view = sender as MenuFlyoutItem;
// 替换为实际的数据类型
if (view?.DataContext is DataObject clickedItem)
{
if (!clickedItem.IsRwmod)
{
new Editor.EditorWin(clickedItem.Dri).Show();
}
}
}
}
public class MyItemTemplateSelector : DataTemplateSelector