我正在尝试使用WPF和MVVM重新创建文件资源管理器。我得到了一个TreeView和ListBox,这两个都能正常工作,只要我做的唯一一件事就是浏览文件夹。当我尝试复制和粘贴文件时,它不会重绘屏幕,我需要取消选择并重新选择文件夹才能看到更新的项目列表。
(To澄清一下,我添加了额外的代码,因为我怀疑我的问题与ObservableCollection
s没有直接关系,也许它与我如何实现所有内容有关。
我的项目概述如下:
我使用视图模型FileViewModel
和FolderViewModel
表示每个文件夹或文件。FolderViewModel更有趣,它包含两个字符串,一个是完整路径,一个是文件名,还有一个ObservableCollection
,包含一个给定文件夹的内容,当检索内容时,该文件夹是延迟加载的。这是FolderViewModel
。我省略了所有不相关的+文件ObservableCollection
和类似于Move
的方法:
public class FolderViewModel : FileFolderBaseViewModel
{
public TrulyObservableCollection<FileFolderBaseViewModel> _folders;
private ICommand _paste;
public ICommand PasteClicked
{
get => _paste;
set
{
_paste = value;
RaisePropertyChanged();
}
}
public TrulyObservableCollection<FileFolderBaseViewModel> Folders
{
get
{
if (_folderModel.HasDummy)
{
_folders.Clear();
PopulateFoldersOnDemand();
}
return _folders;
}
set { _folders = value; RaisePropertyChanged(); }
}
public override bool IsSelected
{
get => _folderModel.IsSelected;
set
{
if (value != _folderModel.IsSelected)
{
_folderModel.IsSelected = value;
RaisePropertyChanged();
//Remove contents only if not expanded and not selected
if (!_folderModel.IsSelected && !_folderModel._isExpanded)
{
if (_folders.Count() > 0)
{
_folderModel.HasDummy = true;
Folders.Clear();
Files.Clear();
Folders.Add(new FileViewModel(new FileModel("dummy", "dummy")));
}
}
}
}
}
public bool IsExpanded
{
get => _folderModel._isExpanded;
set
{
if (value != _folderModel._isExpanded)
{
_folderModel._isExpanded = value;
RaisePropertyChanged();
//Remove contents only if not expanded and not selected
if (!_folderModel._isExpanded && !_folderModel.IsSelected)
{
if (_folders.Count() > 0)
{
_folders.Clear();
_files.Clear();
_folderModel.HasDummy = true;
Folders.Add(new FileViewModel(new FileModel("dummy", "nopath")));
}
}
}
}
}
public FolderViewModel(FolderModel folderModel, TrulyObservableCollection<FileFolderBaseViewModel> contents) : base(folderModel)
{
_files = new TrulyObservableCollection<FileFolderBaseViewModel>(contents.OfType<FileViewModel>());
_folders = new TrulyObservableCollection<FileFolderBaseViewModel>(contents.OfType<FolderViewModel>());
if (Directory.GetDirectories(_folderModel.FilePath).Any())
{
_folderModel.HasDummy = true;
_folders.Add(new FileViewModel(new FileModel("dummy", "nopath")));
}
_paste = new RelayCommand(new Action<object>(HandlePaste));
}
private void Move(FileFolderBaseViewModel file)
{
try
{
if (file is FileViewModel f)
{
File.Move(file.FilePath, FilePath + "\\" + file.FileName, true);
}
else
{
Directory.Move(file.FilePath, FilePath + "\\" + file.FileName);
}
}
catch (Exception e)
{
MessageBox.Show(e.ToString(), "Error", MessageBoxButton.OK);
return;
}
}
private void HandlePaste(object obj)
{
if (ClipBoardItem is not null)
{
if (PreviousRightClickAction is RightClickAction.Move)
{
if (File.Exists(FilePath + "\\" + ClipBoardItem.FileName))
{
MessageBoxResult retVal = MessageBox.Show("File already exists. Overwrite?", "Warning", MessageBoxButton.YesNoCancel, MessageBoxImage.Warning);
if (retVal != MessageBoxResult.Yes)
{
return;
}
}
Files.Add(ClipBoardItem);
Move(ClipBoardItem);
}
...
}
}
private void HandleClickListBoxFolder(object obj) => IsSelected = true;
private void PopulateFoldersOnDemand()
{
string[] dirs = Directory.GetDirectories(_folderModel.FilePath);
FileFolderBaseModel model;
foreach (string dir in dirs)
{
DirectoryInfo inf = new DirectoryInfo(dir);
model = new FolderModel(inf.Name, inf.FullName);
_folders.Add(new FolderViewModel((FolderModel)model, new TrulyObservableCollection<FileFolderBaseViewModel>()));
}
}
}
然后我有FileExplorerViewModel
,它包含两个ObservableCollection
,一个用于TreeView
文件夹,另一个用于ListBox
项目,这取决于TreeView
中所选的文件夹:
public class FileExplorerViewModel : BaseViewModel
{
private ICommand _selectedItemChanged;
public TrulyObservableCollection<FileFolderBaseViewModel> ListViewItems { get; set; }
public TrulyObservableCollection<FolderViewModel> Folders { get; set; }
public ICommand ChangeRoot
{
get => _changeRoot;
set {_changeRoot = value;}
}
public ICommand SelectedItemChanged
{
get => _selectedItemChanged;
set { _selectedItemChanged = value;}
}
public FileFolderBaseViewModel? SelectedItem
{
get => FileFolderBaseModel.SelectedItem;
set
{
if(FileFolderBaseModel.SelectedItem != value)
{
FileFolderBaseModel.SelectedItem = value;
RaisePropertyChanged();
if (FileFolderBaseModel.SelectedItem is FolderViewModel selectedFolder)
{
ListViewItems.Clear();
foreach (var item in selectedFolder.Folders)
{
ListViewItems.Add(item);
}
foreach (var item in selectedFolder.Files)
{
ListViewItems.Add(item);
}
}
}
}
}
public FileExplorerViewModel()
{
_rootDirectory = "C:";
ListViewItems = new TrulyObservableCollection<FileFolderBaseViewModel>();
Folders = new TrulyObservableCollection<FolderViewModel>();
PopulateFolders();
_selectedItemChanged = new RelayCommand(new Action<object>(HandleListViewItemChanged));
}
private void HandleListViewItemChanged(object obj) => SelectedItem = (FileFolderBaseViewModel)obj;
private void PopulateFolders()
{
string[] directoryPaths = Directory.GetDirectories(RootDirectory);
foreach (string f in directoryPaths)
{
FileAttributes attributes = File.GetAttributes(@f);
if (attributes.HasFlag(FileAttributes.Hidden) || attributes.HasFlag(FileAttributes.System))
{
continue;
}
Folders.Add((FolderViewModel)CreateFolderItem(f));
}
}
private FileFolderBaseViewModel CreateFolderItem(string path)
{
DirectoryInfo dirInfo = new DirectoryInfo(path);
return
new FolderViewModel(
new FolderModel(dirInfo.Name, path), new TrulyObservableCollection<FileFolderBaseViewModel>());
}
}
我尝试实现一个TrulyObservableCollection
,这样修改TrulyObservableCollection
中的一个项目就会触发一个CollectionChanged
事件,应用程序就会被重绘。然后,当我将一个项目粘贴到一个文件夹中时,要么项目也被复制/移动到对象中,要么内容列表使用Directory.GetFiles
和Directory.GetDirectories
重新获取所有文件和文件夹。
我还尝试使用FileSystemWatcher
来触发CollectionChanged
事件,但也不起作用。
1条答案
按热度按时间epfja78i1#
通过在
FileExplorerViewModel
中使用FileSystemWatcher
并重新填充ObservableCollection
,我可以在将项目移动或复制到打开的文件夹中时立即管理和重绘应用程序。