Re: WPF Hint
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.11.09 19:46
Оценка:
Здравствуйте, capgoat, Вы писали:

C>Что нового в новой версии:

C>1. Появились свойства ProportionalFontFamily, ProportionalFontSize — для тэга code,
C>FixedFontFamily, FixedFontSize — для остальных
C>2. Новая обработка параметров
C><params>
C><param attrs="[NotNull]" name="loc" typeShortName="Location" typeFullName="Nemerle.Compiler.Location">description</param>
C><param .../>
C><param .../>
C></params>
C>Тут есть замечания:
C>- как обрабатывать attrs(примерчик бы)
C>- description реализован как сабхинт к name и к type, может надо было как-то иначе
C>- name и type некликабельные, т.е. для них нельзя задать handler, а может оно и не надо

Я тут уже прикрутил прошлую версию:
http://www.rsdn.ru/forum/prj.nemerle/3587213.1.aspx
Автор: VladD2
Дата: 30.10.09

http://www.rsdn.ru/forum/prj.nemerle/3589689.1.aspx
Автор: VladD2
Дата: 02.11.09


Причем пришлось несколько изменить код. Так что теперь нужно слить твои и мои изменения.

Итак, что я сделал.
1. Я отключил парсинг параметров с помощью регексов. Вместо этого я стал задавать параметры явно, с помощью тегов <params>, <pname> и <ptype>. Сразу же выяснилось, что "табличное" форматирование (т.е. поддержка котлонок) нужно не только для параметров, но и в других местах. Так что нужно назвать это дело как-то нейтрально и реализовать поддержку более чем двух колонок (обычно нужно будет 2-4, но лучше если не фиксировать их количество явно).

2. Я изменил формат тега <hint>. Теперь он выглядит так:
<hint value='текст отображаемый вместо данного тега' key='ключ' handler='обработчик'>ХМЛ вложенного хинта</hint>

Суть в том, что вложенный хинт может быть столь же навороченным как и основной. Так что его разметку просто нельзя запихать в значение атрибута. А вот текст который отображается вместо тега вложенного хинта как раз без проблем кладется в атрибут.
Что такое handler я думаю объяснять не надо. А вот key нужно пояснить.
Дело в том, что хинты (по крайней мере) для типов нельзя сформировать сразу. Если попытаться это сделать, то в лучшем случае можно получить очень объемный код хинта, а в худщем получить зацикливание. Так вот поле key позволяет не задавать текст хинта сразу, а подгружать его по мере надобности (когда пользователь подводит курсор мыши к активной зоне).
Для работы этого нового ключа я добавил в class Hint поле:
private Func<string, string> _getHintContent;

которое задается параметром метода Show. Кстати, я добавил еще одну перегрузку этого метода:
public void Show(IntPtr owner, Rect placementRect, Func<string, string> getHintContent, string text)

так как удобнее задавать эти параметры при каждом вызове, а пихать их в свойства.
Типичный обработчик передаваемый через это поле выглядит так:
def makeTypeStr(key : string) : string
{
  def ty = idToTypeMap[int.Parse(key)];
  def cnv = Convert();
  cnv.ConvertTypeName = convertTypeName;
  $"<hint>$(cnv.FixedTypeToString(ty))</hint>"
}

т.е. ищет тип в ассоциативном массиве и генерирует хинт для найденного типа. Ключ при этом генерируется как простая последовательность чисел:
mutable currentId = 1;
def idToTypeMap = Hashtable();
def getTyId(ty) : int
{
  currentId++;
  idToTypeMap.Add(currentId, ty);
  currentId
}

def convertTypeName(ty, name)
{
  $"<font color='DarkCyan'><hint value='$name' key='$(getTyId(ty))' /></font>"
}

понятно, что если задан атрибут key, то тело тега <hint> игнорируется (так как оно получается динамически).

C>Парсинг:

C>Основная сложность возникает из-за тэга pre.
C>Вне его все пробельные символы должны заменяться на пробел(эмуляция html).
C>Кроме того, после парсинга в выходной структуре для построения UI этого тэга не должно быть.
C>В предыдущей версии были некоторые сложности из-за динамического params,
C>сейчас этот код благополучно убран.

Я тоже его закоментировал. Вместо этого дабавляю теги <params>, <pname> и <ptype> вручную.
Кстати, оказалось, что табличный вывод удобен не только для отображения параметров, так что логично было бы обобщить этот прием. Нужно что-то типа табулируемого при переносе текста. Так чтобы в нем было от одной, до четырех колонок (лучше конечно чтобы этот дело вычислялось динамически или задавалось бы атрибутом). Я вижу это себе примерно так:
<tbl>
  <row><col><keyword>this</keyword></col><col>param1</col><col>: Type1, </col></row>
  <row><col>[NotNull]</col>              <col>param2</col><col>: Type2</col></row>
</tbl>

Естественно, что все лишние пробелы должны игнорироваться (как в HTML).

C>Краткое описание классов:

C>класс RootText — содержит исходный текст в виде массива символов

А зачем он?

C>Также добавил немного комментов и почистил код.


Очень жаль, что все это не в той весрии, что я уже использую. Не мог бы ты их слить? Но оставить мой вариант тега hint.

C>Надеюсь теперь будет полегче с пониманием.


Я тоже надеюсь.

C>PS В svn коммить лучше сам


Во с этим проблема.
Я все же не доконца понимаю все вещи. Особенно там где чистых ВПФ. Все эти зависимые свойства для меня темный лес.
Я чтобы прикрутить новый обработчик был вынужден протащить его через твой код анализа ХМЛ (в качестве параметра ко всем функциям) и это потому, что я не смог разобраться с тем как реализовать обратный вызов (колбэк) через механизмы ВПФ.

ЗЫ

Кстати, есть очень большая проблема! Хинт периодически сносит всю студию!!!
Из под отладчика я вроде бы вычислил, что проблема в том, что происходит вызов делегата ссылка на который уже уничтожена:

CallbackOnCollectedDelegate was detected
Message: A callback was made on a garbage collected delegate of type 'WpfHint!WpfHint.Win32+Callback::Invoke'. This may cause application crashes, corruption and data loss. When passing delegates to unmanaged code, they must be kept alive by the managed application until it is guaranteed that they will never be called.

по всей видимости — это что-то из химии связанной с сабласиньем окна (перехватом его очереди сообщений). Но я могу ошибаться. Надо это как можно скорее пофиксить!
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.