2010-05-04 2 views
0

У меня есть NSOutlineView с флажками. У меня состояние флажка привязано к элементу узла с ключом shouldBeCopied. В пункте узла у меня есть методы получения и установки, как так:NSOutlineView не перерисовывается

-(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, а затем обратно, и это все, что я хочу, так как я могу заставить его вести себя таким образом?

+0

Есть ли флажки в отдельной колонке таблицы или вы сделали их частью контура столбца? – Alex

+0

Похоже, что ваш дизайн неправильный, ваш объект модели говорит, что делать. Это задача контроллера. Почему у вас есть представление, установленное как делегат объекта модели, вне меня, это полностью назад. Внедрите контроллер, который является делегатом представления. Затем контроллер контролирует обновления модели и сообщает, что просмотр обновляется по мере необходимости. –

+0

@Alex - флажки находятся в колонке контура. @Rob, см. Мой ответ Джошуа. – Septih

ответ

1

У меня есть NSOutlineView с флажками. У меня состояние флажка привязано к элементу узла с ключом shouldBeCopied.

Вы связываете колонку или ячейку? Вы должны привязать столбец.

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

Не было бы лучше использовать значение ребенка в первую очередь? Если ничего другого, дешевле получить (не требуется сообщение).

Измененный добытчик будет выглядеть следующим образом:

- (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-уведомления о своем собственном изменении; ни один объект не отправляет уведомления о свойствах других объектов.

Возможно, у вас может возникнуть соблазн, чтобы ребенок не отправлял эти уведомления KVO, когда его собственное значение для свойства равно YES, потому что в этом случае значение родителя не имеет значения. Вы не должны, так как это будет работать только для детей; если у более далекого потомка есть свойство, установленное на NO, тогда значения предков этого объекта в конце концов будут иметь значение, и этот объект получит уведомление только в том случае, если каждый из его предков разместит его.

+0

Вот и все получилось. Спасибо. Я пошел на более чистый вариант, так как я уже использую 10.5 компонентов. – Septih

1

Ваш сеттер не отправляет -willChangeValueForKey: и -didChangeValueForKey: до и после изменения, поэтому изменения не будут «замечены» механизмом привязок.

Кроме того, сообщение ничего непосредственно с объекта модели ... не является хорошим подходом. В этом случае, поскольку вы используете Bindings, ваш контроллер дерева должен отметить изменение (после того, как вы исправите сеттер для отправки правильных уведомлений) и обновите представление схемы.

+0

ОК, ну, добавив звонки -will/didChangeValueForKey, ничего не изменилось (представление было обновлено для флажка, нажатого с исходным кодом), но я думаю, что это какао, компенсировавшее отсутствие их раньше. Я знаю, что диспетчер должен иметь дело с представлением, но, глядя на то, как обнаружить изменение флажка, все, что я мог видеть в уведомлениях для контурного представления, - это те, которые касаются расширения и выбора изменений, ничего о фактическом содержимое изменяется. Итак, как я должен это обнаруживать в контроллере? Обнаружение кликов в представлении кажется сверху. – Septih

+0

Вам нужно более подробно описать дизайн, чтобы кто-нибудь сделал более конкретные предложения. Там просто недостаточно информации, чтобы дать вам что-нибудь лучше. Расскажите нам, как и как связаны вещи, их ключевые пути (так что у нас есть четкое изображение) и т. Д. –

+0

Сетчатам не нужно отправлять уведомления KVO для 'self' явно, если вы явно не отключили автоматические уведомления. –