wpf 集合更改后未重绘应用程序

35g0bw71  于 2023-10-22  发布在  其他
关注(0)|答案(1)|浏览(138)

我正在尝试使用WPF和MVVM重新创建文件资源管理器。我得到了一个TreeView和ListBox,这两个都能正常工作,只要我做的唯一一件事就是浏览文件夹。当我尝试复制和粘贴文件时,它不会重绘屏幕,我需要取消选择并重新选择文件夹才能看到更新的项目列表。
(To澄清一下,我添加了额外的代码,因为我怀疑我的问题与ObservableCollection s没有直接关系,也许它与我如何实现所有内容有关。
我的项目概述如下:
我使用视图模型FileViewModelFolderViewModel表示每个文件夹或文件。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.GetFilesDirectory.GetDirectories重新获取所有文件和文件夹。
我还尝试使用FileSystemWatcher来触发CollectionChanged事件,但也不起作用。

epfja78i

epfja78i1#

通过在FileExplorerViewModel中使用FileSystemWatcher并重新填充ObservableCollection,我可以在将项目移动或复制到打开的文件夹中时立即管理和重绘应用程序。

相关问题