Home > Mobile >  Enabling and Disabling CommandGroup Menu Items
Enabling and Disabling CommandGroup Menu Items

Time:01-11

I have a very simple sample macOS application with one custom menu command just in order to test my ideas as follows.

import SwiftUI

@main
struct MenuMonsterMacApp: App {
    @State var fileOpenEnabled: Bool = true
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .frame(width: 480.0, height: 320.0)
        }.commands {
            CommandGroup(after: .newItem) {
                Button {
                    print("Open file, will you?")
                } label: {
                    Text("Open...")
                }
                .keyboardShortcut("O")
                .disabled(false)
            }
        }
    }
}

And I want to enable and disable this command with a click of a button that is placed in ContentView. So I've created an ObservableObject class to observe the boolean value of the File Open command as follows.

import SwiftUI

@main
struct MenuMonsterMacApp: App {
    @ObservedObject var menuObservable = MenuObservable()
    @State var fileOpenEnabled: Bool = true
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .frame(width: 480.0, height: 320.0)
        }.commands {
            CommandGroup(after: .newItem) {
                Button {
                    print("Open file, will you?")
                } label: {
                    Text("Open...")
                }
                .keyboardShortcut("O")
                .disabled(!fileOpenEnabled)
            }
        }.onChange(of: menuObservable.fileOpen) { newValue in
            fileOpenEnabled = newValue
        }
    }
}

class MenuObservable: ObservableObject {
    @Published var fileOpen: Bool = true
}

In my ContentView, which virtually runs the show, I have the following.

import SwiftUI

struct ContentView: View {
    @StateObject var menuObservable = MenuObservable()
    
    var body: some View {
        VStack {
            Button {
                menuObservable.fileOpen.toggle()
            } label: {
                Text("Click to disable 'File Open'")
            }
        }
    }
}

If I click on the button, the boolean status of the menu command in question won't change. Is this a wrong approach? If it is, how can enable and disable the menu command from ContentView? Thanks.

CodePudding user response:

To enable and disable the command with a click of a button that is placed in ContentView, try the following approach, using passing environmentObject and a separate View for the menu Button.

import SwiftUI

@main
struct MenuMonsterMacApp: App {
    @StateObject var menuObservable = MenuObservable()

    var body: some Scene {
        WindowGroup {
            ContentView().environmentObject(menuObservable)
                .frame(width: 480.0, height: 320.0)
        }.commands {
            CommandGroup(after: .newItem) {
                OpenCommand().environmentObject(menuObservable)
            }
        }
    }
  
}

struct OpenCommand: View {
    @EnvironmentObject var menuObservable: MenuObservable
    
    var body: some View {
        Button {
            print("Open file, will you?")
        } label: {
            Text("Open...")
        }
        .disabled(!menuObservable.fileOpen)
        .keyboardShortcut("O")
    }
}

class MenuObservable: ObservableObject {
    @Published var fileOpen: Bool = true
}

struct ContentView: View {
    @EnvironmentObject var menuObservable: MenuObservable
    
    var body: some View {
        VStack {
            Button {
                menuObservable.fileOpen.toggle()
            } label: {
                Text("Click to disable 'File Open'")
            }
        }
    }
}
  •  Tags:  
  • Related