如何在WinUI3中基于MVVM实现菜单栏MRU(最近使用文件)列表
基于MVVM实现WinUI3中菜单栏的最近使用文件(MRU)列表
核心思路
要符合MVVM规范,关键是把MRU列表的数据和业务逻辑放到ViewModel中,通过数据绑定让UI自动响应变化,避免直接在后台代码操作UI元素。WinUI的MenuFlyoutSubItem支持ItemsSource绑定,配合ObservableCollection(而非普通List)就能实现动态更新。
步骤1:在ViewModel中定义MRU数据和命令
假设你用Template Studio生成的项目,ShellViewModel继承自ObservableObject,我们在这里添加MRU相关的属性和命令:
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using System.Collections.ObjectModel; using System.IO; namespace YourAppName.ViewModels; public partial class ShellViewModel : ObservableObject { // 存储MRU文件路径的可观察集合,自动通知UI更新 [ObservableProperty] private ObservableCollection<string> _mruItems = new(); // 打开MRU文件的命令 [RelayCommand] private void OpenMruFile(string filePath) { // 这里写打开文件的逻辑,比如启动对应的页面或调用文件处理方法 if (File.Exists(filePath)) { // 示例:处理文件打开 } } // 添加文件到MRU列表的方法(可在其他地方调用,比如打开文件后) public void AddToMru(string filePath) { // 先移除已存在的项,避免重复 if (_mruItems.Contains(filePath)) { _mruItems.Remove(filePath); } // 把最新的文件放到列表最顶部 _mruItems.Insert(0, filePath); // 限制MRU列表的最大数量(比如最多10个) const int maxMruCount = 10; while (_mruItems.Count > maxMruCount) { _mruItems.RemoveAt(_mruItems.Count - 1); } } }
步骤2:修改XAML绑定UI
在ShellPage.xaml中,修改你的MenuFlyoutSubItem,通过ItemsSource绑定ViewModel的MruItems,并使用ItemTemplate定义每个菜单项的样式和命令绑定:
<!-- 假设你的MenuFlyoutSubItem在某个MenuBarItem的Flyout里 --> <MenuBarItem Text="文件"> <MenuBarItem.Flyout> <MenuFlyout> <!-- 其他菜单项 --> <MenuFlyoutSubItem Text="最近使用文件" ItemsSource="{Binding MruItems}"> <MenuFlyoutSubItem.ItemTemplate> <DataTemplate> <MenuFlyoutItem Text="{Binding}" Command="{Binding DataContext.OpenMruFileCommand, RelativeSource={RelativeSource AncestorType=MenuFlyoutSubItem}}" CommandParameter="{Binding}"/> </DataTemplate> </MenuFlyoutSubItem.ItemTemplate> </MenuFlyoutSubItem> </MenuFlyout> </MenuBarItem.Flyout> </MenuBarItem>
步骤3:触发MRU列表更新
当用户打开一个新文件时,直接调用ViewModel的AddToMru方法即可,比如在文件打开的ViewModel或页面中:
// 假设你拿到了用户选择的文件路径 string selectedFilePath = "C:\\TestFile.txt"; // 获取ShellViewModel实例(Template Studio项目中可通过Ioc.Default.GetRequiredService<ShellViewModel>()获取) var shellVm = Ioc.Default.GetRequiredService<ShellViewModel>(); shellVm.AddToMru(selectedFilePath);
额外优化:持久化MRU列表
如果需要关闭应用后保留MRU列表,可以在ViewModel的构造函数中从本地加载,在列表变化时保存到本地:
using Windows.Storage; public ShellViewModel() { // 从本地加载MRU列表 LoadMruFromLocal(); } private void LoadMruFromLocal() { var localSettings = ApplicationData.Current.LocalSettings; if (localSettings.Values.TryGetValue("MruList", out var mruObj) && mruObj is string[] mruArray) { foreach (var filePath in mruArray) { // 检查文件是否存在,避免无效路径 if (File.Exists(filePath)) { _mruItems.Add(filePath); } } } } private void SaveMruToLocal() { var localSettings = ApplicationData.Current.LocalSettings; localSettings.Values["MruList"] = _mruItems.ToArray(); } // 重写ObservableObject的OnPropertyChanged,在MruItems变化时保存 protected override void OnPropertyChanged(PropertyChangedEventArgs e) { base.OnPropertyChanged(e); if (e.PropertyName == nameof(MruItems)) { SaveMruToLocal(); } }
内容的提问来源于stack exchange,提问作者Zulu
相关产品推荐
相关产品推荐

