NSOutlineView没有重绘

时间:2010-05-04 13:18:50

标签: cocoa cocoa-bindings nsoutlineview

我有一个带复选框的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然后再返回时,显示器会刷新,这就是我想要的,所以我怎么能让它表现得那样呢?

2 个答案:

答案 0 :(得分:1)

你的setter不会在更改之前和之后发送-willChangeValueForKey:和-didChangeValueForKey:因此绑定机制不会“注意到”这些更改。

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

答案 1 :(得分:1)

  

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

您是绑定列还是单元格?你应该绑定列。

-(BOOL)shouldBeCopied {
    if([[self parent] shouldBeCopied])
        return YES;
    return 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通知。每个对象应该只声称知道自己属性的值;声称知道另一个对象的属性的值的对象可能存在错误,导致错误和/或低效的行为,更不用说代码引发头痛的倾向。

更干净的解决方案是让每个对象都观察其父对象的这个属性。在将自己添加为观察者时通过the NSKeyValueObservingOptionPrior option,以便在更改之前收到通知(您将在the observation method中通过发送[self willChangeValueForKey:]来回复)并在更改后收到通知(您将在观察方法中通过发送[self didChangeValueForKey:])来回复。

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

当孩子自己的属性值为YES时,你可能会想让孩子不发送这些KVO通知,因为在这种情况下,父母的值无关紧要。但是,你不应该这样做,因为这只适用于儿童;如果一个较低的后代将属性设置为NO,那么该对象的祖先的值毕竟是重要的,并且该对象只会在其每个祖先发布它时才会收到通知。