NSOutlineView 不重绘

发布于 2024-08-31 03:12:19 字数 719 浏览 7 评论 0原文

我有一个带有复选框的 NSOutlineView 。我将复选框状态绑定到带有键 shouldBeCopied 的节点项。在节点项中,我有如下的 getter 和 setter:

-(BOOL)shouldBeCopied {
    if([[self parent] shouldBeCopied])
        return YES;
    return shouldBeCopied;
}

-(void)setShouldBeCopied:(BOOL)value {
    shouldBeCopied = value; 
    if(value && [[self children] count] > 0)
        [[self delegate] reloadData];
}

这里的想法是,如果检查了父项,则子项也应该检查。我遇到的问题是,当我检查父级时,如果子级已经展开,它不会更新子级的视图。我可以理解它不应该由绑定更新,因为我实际上并没有更改该值。但是 reloadData 是否应该不会导致绑定重新获取值,从而为子级调用 -shouldBeCopied ?我尝试了其他一些方法,例如 -setNeedsDisplay-reloadItem:nil reloadChildren:YES 但没有任何效果。我注意到,当我切换到 xcode 然后再返回时,显示会刷新,这就是我想要的,那么我该如何让它表现得这样呢?

I have an NSOutlineView with checkboxes. I have the checkbox state bound to a node item with the key shouldBeCopied. In the node item I have the getters and setters like so:

-(BOOL)shouldBeCopied {
    if([[self parent] shouldBeCopied])
        return YES;
    return shouldBeCopied;
}

-(void)setShouldBeCopied:(BOOL)value {
    shouldBeCopied = value; 
    if(value && [[self children] count] > 0)
        [[self delegate] reloadData];
}

The idea here is that if the parent is checked, so should the children. The problem I'm having is that when I check the parent, it does not update that view of the children if they are already expanded. I can understand that it should not be updated by the bindings because i'm not actually changing the value. But should reloadData not cause the bindings to re-get the value, thus calling -shouldBeCopied for the children? I have tried a few other things such as -setNeedsDisplay and -reloadItem:nil reloadChildren:YES but none work. I've noticed that the display gets refreshed when I swap to xcode and then back again and that's all I want, so how do I get it to behave that way?

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

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

发布评论

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

评论(2

飘逸的'云 2024-09-07 03:12:19

我有一个带有复选框的 NSOutlineView。我将复选框状态绑定到带有键 shouldBeCopied 的节点项。

你是绑定柱子还是细胞?您应该绑定该列。

<前><代码>-(BOOL)shouldBeCopied {
if([[自身父级] shouldBeCopied])
返回是;
返回应该被复制;
}

先利用孩子的价值不是更好吗?如果不出意外的话,检索起来会更便宜(不需要消息)。

修改后的 getter 将如下所示:

- (BOOL) shouldBeCopied {
     return (shouldBeCopied || [[self parent] shouldBeCopied]);
}

我遇到的问题是,当我检查父级时,如果子级已经展开,它不会更新子级的视图。

有两种解决方案。其中一个更干净,可以在 10.5 及更高版本上运行。另一个有点脏,可以在任何版本的 Mac OS X 上工作。

脏的解决方案是让父级通过 setter 方法代表其所有子级发布 KVO 通知。类似于:

[children performSelector:@selector(willChangeValueForKey:) withObject:@"shouldBeCopied"];
//Actually change the value here.
[children performSelector:@selector(didChangeValueForKey:) withObject:@"shouldBeCopied"];

这是脏的,因为它有一个对象发布有关另一对象属性的 KVO 通知。每个对象应该只声称知道自己属性的值;一个声称知道另一个对象属性值的对象可能会出错,从而导致错误和/或低效的行为,更不用说代码可能会引起头痛。

更干净的解决方案是让每个对象观察其父对象的此属性。通过 将自己添加为观察者时的 NSKeyValueObservingOptionPrior 选项,以便在更改之前收到通知(您将在 观察方法,通过发送[self willChangeValueForKey:])以及更改后的通知(您可以在观察方法中,将通过发送 [self didChangeValueForKey:])。

使用干净的解决方案,每个对象仅发送有关其自身属性更改的 KVO 通知;没有对象正在发布有关其他对象属性的通知。

当子进程自己的属性值为 YES 时,您可能想让子进程不向自己发送这些 KVO 通知,因为在这种情况下,父进程的值并不重要。不过,你不应该这么做,因为这只对儿童有效。如果一个更向下的后代将属性设置为NO,那么该对象的祖先的值毕竟很重要,并且该对象只有在其每个祖先都发布通知时才会收到通知。

I have an NSOutlineView with checkboxes. I have the checkbox state bound to a node item with the key shouldBeCopied.

Are you binding the column or the cell? You should bind the column.

-(BOOL)shouldBeCopied {
    if([[self parent] shouldBeCopied])
        return YES;
    return shouldBeCopied;
}

Would it not be better to use the child's value first? If nothing else, it's cheaper to retrieve (no message required).

The amended getter would then look like this:

- (BOOL) shouldBeCopied {
     return (shouldBeCopied || [[self parent] shouldBeCopied]);
}

The problem I'm having is that when I check the parent, it does not update that view of the children if they are already expanded.

There are two solutions. One is cleaner and will work on 10.5 and later. The other is slightly dirty and will work on any version of Mac OS X.

The dirty solution is to have the parent, from the setter method, post KVO notifications on behalf of all of its children. Something like:

[children performSelector:@selector(willChangeValueForKey:) withObject:@"shouldBeCopied"];
//Actually change the value here.
[children performSelector:@selector(didChangeValueForKey:) withObject:@"shouldBeCopied"];

This is dirty because it has one object posting KVO notifications about a property of another object. Each object should only claim to know the values of its own properties; an object that claims to know the values of another object's properties risks being wrong, leading to wrong and/or inefficient behavior, not to mention a propensity for the code to induce headache.

The cleaner solution is to have each object observe this property of its parent. Pass the NSKeyValueObservingOptionPrior option when adding yourself as an observer in order to get a notification before the change (which you'll respond to, in the observation method, by sending [self willChangeValueForKey:]) and a notification after the change (which you'll respond to, in the observation method, by sending [self didChangeValueForKey:]).

With the clean solution, each object only sends KVO notifications about its own property changing; no object is posting notifications about other objects' properties.

You might be tempted to have the child not send itself these KVO notifications when its own value for the property is YES, because in that case the parent's value doesn't matter. You shouldn't, though, as this would only work for children; if a farther-down descendant has the property set to NO, then that object's ancestors' values matter after all, and that object will only get the notification if every one of its ancestors posts it.

初心 2024-09-07 03:12:19

您的设置器在更改之前和之后不会发送 -willChangeValueForKey: 和 -didChangeValueForKey: ,因此绑定机制不会“注意到”更改。

另外,直接从模型对象告诉视图任何都不是一个好方法。在这种情况下,由于您正在使用绑定,因此您的树控制器应该记录更改(一旦您修复了设置器以发送正确的通知)并更新大纲视图。

Your setter does not send -willChangeValueForKey: and -didChangeValueForKey: before and after the change, therefore the changes won't be "noticed" by the bindings mechanism.

Also, telling a view anything directly from a model object is ... not a good approach. In this case, since you're using Bindings, your tree controller should note the change (once you fix your setter to send the proper notifications) and update the outline view.

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