简体   繁体   English

为什么此绑定在 macOS 上的子视图中不起作用?

[英]Why doesn't this binding work when it's in a subview on macOS?

I have a couple layers of ObservableObjects and Published properties.我有几层 ObservableObjects 和 Published 属性。 When I use them directly in a view, they seem to work as expected.当我直接在视图中使用它们时,它们似乎按预期工作。 However, when I try to move the list into it's own type, the bindings in the parent view don't seem to work.但是,当我尝试将列表移动到它自己的类型时,父视图中的绑定似乎不起作用。

For example, why the ModelList is enabled, when you select rows, the Button does not toggle between enabled and disabled.例如,为什么启用了 ModelList,当您选择行时,Button 不会在启用和禁用之间切换。 However, if you comment that out and enable the List.init lines, then when selecting and unselecting rows, the Button correctly enables and disables.但是,如果您将其注释掉并启用 List.init 行,则在选择和取消选择行时,按钮会正确启用和禁用。

https://youtu.be/7Kvh2w8z__4 https://youtu.be/7Kvh2w8z__4

This works这有效

View
 List(selection: viewModel.dataStore.selection)

This does not这不

View
 ModelList(dataStore: viewModel.dataStore) 
  List(selection: dataStore.selection)

Full code example完整代码示例

import SwiftUI

struct ContentView: View {
    @ObservedObject var viewModel: ViewModel
    
    var body: some View {
        VStack {
            // Using the the dataStore, the button bind works
            //            List.init(viewModel.dataStore.models, id: \.id, selection: $viewModel.dataStore.selection) {
            //                Text("Name: \($0.name)")
            //            }

            // Using the dataStore in the subview, the button binding doesn't work
            ModelList(dataStore: viewModel.dataStore)
            
            Button(action: {
                print("Delete")
            }, label: {
                Image(systemName: "minus")
            })
            .disabled($viewModel.dataStore.selection.wrappedValue.count == 0)
            Text("Selection \($viewModel.dataStore.selection.wrappedValue.count)")
        }
    }
}
struct ModelList: View {
    @ObservedObject public var dataStore: DataStore
    
    var body: some View {
        List.init(dataStore.models, id: \.id, selection: $dataStore.selection) {
            Text("Name: \($0.name)")
        }
    }
}

class ViewModel: ObservableObject {
    @Published var dataStore: DataStore = DataStore()
}
class DataStore: ObservableObject {
    @Published public var selection = Set<Int>()
    @Published public var models = [Model(id: 1, name: "First")]
}

struct Model: Identifiable {
    let id: Int
    let name: String
}

@main
struct LayersApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView(viewModel: ViewModel())
        }
    }
}

The subview should accept a Binding, not another ObservedObject.子视图应该接受一个 Binding,而不是另一个 ObservedObject。

@ObservedObject public var dataStore: DataStore should be @Binding public var dataStore: DataStore @ObservedObject public var dataStore: DataStore应该是@Binding public var dataStore: DataStore

Now when using the subview, pass in the binding ModelList(dataStore: $viewModel.dataStore)现在在使用子视图时,传入绑定ModelList(dataStore: $viewModel.dataStore)

Complete working example:完整的工作示例:

struct ContentView: View {
    @ObservedObject var viewModel: ViewModel
    
    var body: some View {
        VStack {
            ModelList(dataStore: $viewModel.dataStore)
            
            Button(action: {
                print("Delete \(viewModel.dataStore.selection)")
            }, label: {
                Image(systemName: "minus")
            })
            .disabled($viewModel.dataStore.selection.wrappedValue.count == 0)
            Text("Selection \($viewModel.dataStore.selection.wrappedValue.count)")
        }
    }
}
struct ModelList: View {
    @Binding public var dataStore: DataStore

    var body: some View {
        List.init(dataStore.models,
                  id: \.id,
                  selection: $dataStore.selection) {
            Text("Name: \($0.name)")
        }
    }
}

class ViewModel: ObservableObject {
    @Published var dataStore: DataStore = DataStore()
    
    init() {
        print("ViewModel")
    }
}
class DataStore: ObservableObject {
    
    @Published public var selection = Set<Int>()
    @Published public var models = [Model(id: 1, name: "First")]
    
    init() {
        print("DataStore")
    }
}

struct Model: Identifiable, Equatable {
    let id: Int
    let name: String
}

@main
struct LayersApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView(viewModel: ViewModel())
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM