You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 01:45:41