You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在事件触发后通过代码聚焦Mahapps.Metro HamburgerMenu指定菜单项?

如何在Mahapps.Metro的HamburgerMenu中通过代码聚焦特定菜单项

我来帮你搞定这个需求——要让HamburgerMenu的指定菜单项通过代码获得焦点,核心是找到对应菜单项的ViewModel实例,再获取它的可视化容器,最后让容器聚焦。结合你的代码,具体实现步骤如下:

1. 定位目标菜单项的ViewModel实例

你的HamburgerMenu通过ItemsSourceOptionsItemsSource绑定了MenuItem类型的集合,所以首先要从ViewModel里找到要聚焦的那个MenuItem实例。推荐用唯一ID匹配(比文本更可靠),示例如下:

// 假设ViewModel是当前窗口/页面的DataContext
var viewModel = DataContext as YourViewModelType;
// 替换成你要聚焦的菜单项标识,比如自定义的Id属性或Text
var targetMenuItem = viewModel.Menu.FirstOrDefault(item => item.Text == "你的目标菜单项文本");

// 如果是选项菜单里的项,从OptionsMenu中查找
// var targetMenuItem = viewModel.OptionsMenu.FirstOrDefault(item => item.Text == "选项菜单项文本");

2. 获取菜单项的可视化容器

HamburgerMenu的主菜单和选项菜单分别用ItemContainerGeneratorOptionsItemContainerGenerator生成项容器,我们需要通过这两个生成器拿到目标ViewModel对应的HamburgerMenuItem容器:

HamburgerMenuItem targetContainer = null;

if (targetMenuItem != null)
{
    // 判断目标项属于主菜单还是选项菜单
    bool isOptionItem = viewModel.OptionsMenu.Contains(targetMenuItem);
    
    if (isOptionItem)
    {
        targetContainer = HamburgerMenuControl.OptionsItemContainerGenerator.ContainerFromItem(targetMenuItem) as HamburgerMenuItem;
    }
    else
    {
        targetContainer = HamburgerMenuControl.ItemContainerGenerator.ContainerFromItem(targetMenuItem) as HamburgerMenuItem;
    }
}

3. 处理容器未生成的情况

如果代码在HamburgerMenu还没完成容器生成时执行(比如窗口刚加载阶段),ContainerFromItem会返回null。这时需要监听生成器的StatusChanged事件,等容器生成后再聚焦:

private void FocusTargetMenuItem(MenuItem targetItem, bool isOptionItem = false)
{
    HamburgerMenuItem container = null;
    var generator = isOptionItem ? HamburgerMenuControl.OptionsItemContainerGenerator : HamburgerMenuControl.ItemContainerGenerator;

    container = generator.ContainerFromItem(targetItem) as HamburgerMenuItem;

    // 容器未生成时,等待生成完成再处理
    if (container == null && generator.Status == GeneratorStatus.NotStarted)
    {
        EventHandler statusChangedHandler = null;
        statusChangedHandler = (sender, e) =>
        {
            if (generator.Status == GeneratorStatus.ContainersGenerated)
            {
                container = generator.ContainerFromItem(targetItem) as HamburgerMenuItem;
                if (container != null)
                {
                    container.Focusable = true;
                    container.Focus();
                }
                generator.StatusChanged -= statusChangedHandler;
            }
        };
        generator.StatusChanged += statusChangedHandler;
        return;
    }

    // 容器已生成,直接设置焦点
    if (container != null)
    {
        container.Focusable = true;
        container.Focus();
    }
}

4. 调用聚焦方法并处理Pane状态

最后在你的事件触发逻辑里调用这个方法即可。另外,如果HamburgerMenu的Pane处于关闭状态,建议先打开Pane,否则焦点设置后无法直观看到效果:

// 先打开Pane(根据你的需求选择是否添加)
HamburgerMenuControl.IsPaneOpen = true;

// 调用聚焦方法
var viewModel = DataContext as YourViewModelType;
var targetItem = viewModel.Menu.FirstOrDefault(item => item.Text == "目标文本");
if (targetItem != null)
{
    FocusTargetMenuItem(targetItem);
}

额外注意事项

  • 你的自定义ItemTemplate里的元素(ContentControlTextBlock)都设置了Focusable="False",这是合理的——焦点应该落在HamburgerMenuItem容器上,才能正确触发菜单的焦点样式。
  • 建议给MenuItem ViewModel添加唯一标识属性(比如Id),用它匹配目标项比文本更稳定,避免文本修改后代码失效。

内容的提问来源于stack exchange,提问作者Ribas

火山引擎 最新活动