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

如何根据视图状态条件性启用/禁用Command Menu按钮

解决思路与修正代码

问题根源

你遇到的错误核心是ViewState实例不共享:

  • MyApp中用@EnvironmentObject声明了viewState,但没有提前注入对应的实例,导致系统找不到该对象
  • DetailsView里用@StateObject创建了全新的ViewState实例,和MyApp期望的不是同一个,数据完全无法同步

1. 全局注入唯一的ViewState实例

在MyApp结构体中创建唯一的ViewState实例,并通过environmentObject注入到整个视图层级,确保App的命令菜单和所有子视图共享同一个状态对象:

@main
struct MyApp: App {
    // 创建全局唯一的ViewState实例
    @StateObject private var viewState = ViewState()

    var body: some Scene {
        WindowGroup {
            // 替换成你的实际根视图,在这里注入环境对象
            RootView()
                .environmentObject(viewState)
        }
        .commands {
            CommandGroup(after: CommandGroupPlacement.undoRedo) {
                Button("Listeneintrag bearbeiten") {
                    // 执行按钮操作
                }.disabled(!viewState.itemSelected)
            }
        }
    }
}

2. 修改DetailsView使用共享状态

把DetailsView里的@StateObject改为@EnvironmentObject,直接获取App注入的全局ViewState实例,同时注意和App中判断的字段保持一致:

struct DetailsView: View {
    // 获取共享的ViewState实例
    @EnvironmentObject var viewState: ViewState

    var body: some View {
        ZStack(alignment: .bottom) {
            // 你的视图内容
        }
        .onAppear {
            // 和App中按钮判断的字段统一为itemSelected
            viewState.itemSelected = true
        }
        .onDisappear {
            viewState.itemSelected = false
        }
    }
}

3. 关键注意事项

  • 单一实例原则:整个App只需要一个ViewState实例,由@StateObject在MyApp中初始化,其他所有需要访问状态的地方都用@EnvironmentObject获取
  • 字段一致性:确保DetailsView修改的字段和App命令菜单判断的字段是同一个(比如统一用itemSelected)
  • 注入时机:必须在根视图层级注入environmentObject,否则子视图和App命令菜单无法获取到状态对象

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 05:50:32