Post

Replies

Boosts

Views

Activity

SwiftUI, how to use Commands in a document based App
I have a SwiftUI document based app where multiple documents can be open at the same time. I now want to have menu items in the main menu that send commands to the active window. Additionally, I want menu items to be disabled if no matching object is selected in the active window. As an example Finder can be used, where in the "Edit" menu the entries are different depending on the selected files. I tried using a class as shown below to communicate between the views and the Commands structure, which basically works. Unfortunately, this causes a command to arrive at all open documents. And if I have an entry selected in one window but not in another, the AppState object only reflects the last selected state. If I change the window, the app does not notice this for the time being. class AppState: ObservableObject { static let shared = AppState() @Published var dirEntryCommand = PassthroughSubject<DirCommand,Never>() @Published var selectedDirEntry: DirectoryEntry.ID? } The Commands struct looks like this: enum DirCommand: Int, Identifiable, CaseIterable { case rename case moveUp case moveDown var id: RawValue { rawValue } } struct DirEntryCommands: Commands { @ObservedObject var appState = AppState.shared var body: some Commands { CommandMenu("Directory Entry") { Section { Button("Move up") { appState.dirEntryCommand.send(.moveUp) } .keyboardShortcut("u") Button("Move down") { appState.dirEntryCommand.send(.moveDown) } .keyboardShortcut("d") } .disabled(appState.selectedDirEntry == nil) Section { Button("Rename…") { appState.dirEntryCommand.send(.rename) } .keyboardShortcut("r") } .disabled(appState.selectedDirEntry == nil) } } } It is possible that I am taking the wrong approach and that there is another solution to this problem. In a pure AppKit application I would implement the relevant commands in the ViewController and use the "magic" of the ResponderChain.
1
0
976
Mar ’23
SwiftUI, how to use Commands in a document based App
I have a SwiftUI document based app where multiple documents can be open at the same time. I now want to have menu items in the main menu that send commands to the active window. Additionally, I want menu items to be disabled if no matching object is selected in the active window. As an example Finder can be used, where in the "Edit" menu the entries are different depending on the selected files. I tried using a class as shown below to communicate between the views and the Commands structure, which basically works. Unfortunately, this causes a command to arrive at all open documents. And if I have an entry selected in one window but not in another, the AppState object only reflects the last selected state. If I change the window, the app does not notice this for the time being. class AppState: ObservableObject { static let shared = AppState() @Published var dirEntryCommand = PassthroughSubject<DirCommand,Never>() @Published var selectedDirEntry: DirectoryEntry.ID? } The Commands struct looks like this: enum DirCommand: Int, Identifiable, CaseIterable { case rename case moveUp case moveDown var id: RawValue { rawValue } } struct DirEntryCommands: Commands { @ObservedObject var appState = AppState.shared var body: some Commands { CommandMenu("Directory Entry") { Section { Button("Move up") { appState.dirEntryCommand.send(.moveUp) } .keyboardShortcut("u") Button("Move down") { appState.dirEntryCommand.send(.moveDown) } .keyboardShortcut("d") } .disabled(appState.selectedDirEntry == nil) Section { Button("Rename…") { appState.dirEntryCommand.send(.rename) } .keyboardShortcut("r") } .disabled(appState.selectedDirEntry == nil) } } } It is possible that I am taking the wrong approach and that there is another solution to this problem. In a pure AppKit application I would implement the relevant commands in the ViewController and use the "magic" of the ResponderChain.
Replies
1
Boosts
0
Views
976
Activity
Mar ’23