添加编辑行为绑定NSFormCell

发布于 2024-12-19 12:53:24 字数 733 浏览 3 评论 0原文

我有一个带有客户 ID 属性的核心数据模型类。它绑定到表单单元格。当用户完成编辑文本时,我希望有机会将其输入内容转换为大写,使用取决于旧值和新值的逻辑

理想情况下,我希望使用可以在笔尖中实例化的对象并连接到文本单元格,使行为保持靠近其所属的视图。但我会选择一个必须连接到模型的物体。

我已经实现了这三种不同的方式:

  1. 模型类中的自定义 setter 方法
  2. 文本编辑委托实现 NSControlTextEditingDelegate
  3. 使用 KVO 来通知更改并启动后续更改的帮助器类

所有三种实现都有问题。分别存在的问题:

  1. 此行为不属于模型。例如,我应该能够在代码中设置该属性,而无需触发它。
  2. 我无法获取“之前”值,因为表单单元格不提供 controlTextDidBeginEditing: 调用(并且在调用 controlTextDidEndEditing: 时旧值已消失) 。此外,在不输入任何内容的情况下进出字段会触发对 controlTextDidEndEditing: 的调用。
  3. 当针对用户的更改触发观察,并且我启动对该属性的后续更改时,视图会忽略更改通知并且不会重绘。 (我认为绑定器这样做是为了提高效率。通常在更新模型时,它可以忽略正在更新的字段中的 KVO 观察结果。)

您将如何解决这个问题?

I've a Core Data model class with a customer ID attribute. It's bound to a form cell. When the user finishes editing the text I want a chance to convert their entry to upper case, using logic which depends on the old and new values.

Ideally I want to keep the behavior close to the view where it belongs, using an object I can instantiate in the nib and hook up to the text cells. But I'd settle for an object I had to hook up to the model.

I've implemented this three different ways:

  1. Custom setter method in the model class
  2. Text editing delegate implementing NSControlTextEditingDelegate
  3. Helper class which uses KVO to notice the change and initiate a subsequent change

All three implementations have problems. The issues, respectively:

  1. This behavior doesn't belong in the model. I should be able to set the attribute in code, for example, without triggering it.
  2. I can't get the "before" value because the form cell doesn't provide controlTextDidBeginEditing: calls (and the old value is gone by the time controlTextDidEndEditing: is called). Furthermore tabbing in and out of the field without typing anything triggers a call to controlTextDidEndEditing:.
  3. When the observation fires for the user's change, and I initiate a subsequent change to that property, the view ignores the change notification and doesn't redraw. (I presume the binder does this for efficiency. Normally when updating the model, it can ignore the KVO observations from the field being updated.)

How would you solve this problem?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

心的位置 2024-12-26 12:53:24

之后,听起来有一些可能的方法:

  1. 这里进行一些讨论 模型类上的类别并覆盖 validateMyKey
  2. 子类化 NSFormCell

我尝试了两者。更多问题:

  1. 直到模型更新自身后才会调用 validateMyKey,因此旧值不可用。
  2. editWithFrame:inView:editor:delegate:event: 并不总是在输入字段时调用,因此很难访问 endEditing: 中的旧值。

新的解决方案是对我原来的 #2 的改进:文本编辑委托实现 NSControlTextEditingDelegate

仅实现 control:textShouldEndEditing:,而不是 controlTextDidBeginEditing:controlTextDidEndEditing:。在该方法中,如有必要,操作文本,然后返回 YES。

我在笔尖中实例化它并使其成为表单的委托(而不是单元格的委托)。在下面的代码中,我使用 infoForBinding: 获取旧值,但如果您不使用绑定,则可以向模型对象添加一个出口。

-(BOOL)control:(NSControl *)control textShouldEndEditing:(NSText *)fieldEditor {
    NSCell *cell = [(NSForm *)control selectedCell];
    NSString *identifier = [(NSCell *)[(NSForm *)control selectedCell] identifier];
    if (!identifier) return YES;

    NSDictionary *bindingInfo = [cell infoForBinding:@"value"];
    if (!bindingInfo) return YES;
    NSString *oldValue = [[bindingInfo valueForKey:NSObservedObjectKey] valueForKeyPath:[bindingInfo valueForKey:NSObservedKeyPathKey]];

    NSString *newValue = cell.stringValue;

    if ([identifier isEqualTo:@"firstField"]) {
        if (criteria)
            cell.stringValue = ....;
    
    } else if ([identifier isEqualTo:@"secondField"]) {
        if (criteria)
            cell.stringValue = ....;
    }

    return YES;
}

After some discussion here, it sounds like some possible ways to do tho:

  1. Put a category on the model class and override validateMyKey
  2. Subclassing NSFormCell

I tried both. More issues:

  1. validateMyKey isn't called until after the model updates itself, so the old value isn't available.
  2. editWithFrame:inView:editor:delegate:event: isn't always called upon entering a field, so it's difficult to access the old value in endEditing:.

New solution is a refinement on my original #2: text editing delegate implementing NSControlTextEditingDelegate.

Instead of controlTextDidBeginEditing: and controlTextDidEndEditing:, implement only control:textShouldEndEditing:. In that method, manipulate the text if necessary, then return YES.

I instantiate this in the nib and make it the form's delegate (not the cells'). In the code below I get the old value using infoForBinding: but if you aren't using bindings, you could add an outlet to the model object instead.

-(BOOL)control:(NSControl *)control textShouldEndEditing:(NSText *)fieldEditor {
    NSCell *cell = [(NSForm *)control selectedCell];
    NSString *identifier = [(NSCell *)[(NSForm *)control selectedCell] identifier];
    if (!identifier) return YES;

    NSDictionary *bindingInfo = [cell infoForBinding:@"value"];
    if (!bindingInfo) return YES;
    NSString *oldValue = [[bindingInfo valueForKey:NSObservedObjectKey] valueForKeyPath:[bindingInfo valueForKey:NSObservedKeyPathKey]];

    NSString *newValue = cell.stringValue;

    if ([identifier isEqualTo:@"firstField"]) {
        if (criteria)
            cell.stringValue = ....;
    
    } else if ([identifier isEqualTo:@"secondField"]) {
        if (criteria)
            cell.stringValue = ....;
    }

    return YES;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文