¨ Ищется поток, который владеет ресурсом HWND, принадлежащим элементу управления,
¨ Метод Invoke запускает в этом потоке функцию, соответствующую указанному делегатному типу.
Попробуйте на русском выразить эту мысль так же коротко. Если сможете, покажите ваш текст. Как бы там ни было, я не хотел признавать факт наличия еще одного потока, кроме потока, в котором выполняется наше приложение Client, и в адресное пространство которого загружена наша DLL Library. Но ведь меня не спрашивают и COM-объект на самом деле работает в другом потоке. Ситуация с Invoke похожа на посылку сообщения самому себе, как в случае с функцией PostMessage).
PostMessage — традиционный прием Win32-программиста. Он означает: выполни то, что хочешь, но позже, после окончания обработки текущего сообщения и сделай это в функции обратного вызова, то есть реакции на посланное себе же сообщение. Напомню, что рассматриваемая проблема возникла потому, что я забыл установить объект SynchronizingObject.
Синтаксис вызова Invoke мы рассматривали ранее, поэтому не будем к нему возвращаться и отметим лишь, что с помощью Invoke можно решить проблему отладки нашего кода, без установки SynchronizingObject=this. Но при этом код станет значительно менее понятным. Вместо прямого воздействия на узел:
node.Nodes.Add(new TreeNode(GetFolderName(fullPath), id, id + 1));
придется воздействовать на TreeView таким образом:
tree.Invoke(new Action<TreeNode,TreeNode>(DoAdd, node, new TreeNode(GetFolderName(fullPath),id,id+1));
Кроме этого придется добавить метод DoAdd с сигнатурой Action<TreeNode,TreeNode>.
void DoAdd (TreeNode parent, TreeNode node) { parent.Nodes.Add(node); }
Функция, вызываемая с помощью Invoke, должна иметь сигнатуру, соответствующую делегатному типу. В этом месте почти все без исключения говорят—соответствующую делегату, а не делегатному типу. Это упрощение, так как делегат создаеттся с помощью операции new. Головоломно, не правда ли? Но зато все работает всегда. Чтобы избежать путаницы, приведем полный код альтернативной версии реализации события Created.
void AddFolder(string fullPath, bool bHidden)
{
TreeNode node = FindNode(Path.GetDirectoryName(fullPath));
if (node != null)
{
if (node.Tag != null)
{
int id = bHidden ? 16 : 14;
tree.Invoke(new Action<TreeNode,TreeNode>(DoAdd),node,new TreeNode(GetFolderName(fullPath),id,id+1));
}
else
FillFolder(node, 2);
}
}
void OnAddFolder(TreeNode parent, TreeNode node) { parent.Nodes.Add(node); }
Некоторые пояснения особенностей вызова Invoke можно найти в MSDN. Например, массив объектов (new object[]), который создается по ходу дела, позволяет создать делегатный тип с произвольным числом параметров. Мы используем лишь два параметра: родительский узел и дочерний узел, а могли бы передать и два и три и т.д.
Мы познакомились со способом запуска произвольного метода (в нашем случае DoAdd) в рамках другого потока. Запуск метода с помощью Invoke называется синхронным, так как наш (главный) поток, при этом, ждет завершения вспомогательного потока, то есть временно стоит. Особенность синхронного запуска в том, что нам не надо создавать другой поток—он выбирается из специального множества дежурных потоков (thread pool). Метод Invoke автоматически создает другой поток и запускает его в синхронном режиме. Существует и другой способ запуска любого метода любого класса—асинхронный (при этом работает пара методов BeginInvoke-EndInvoke), но об этом в другой раз.
Некоторые наши студенты: Глухов А.А. и Тихановский А.С. проявили нестандартные и весьма интересные подходы к управлению как деревом, так и списком. Их решения надежно работают, но я не готов обсуждать их сейчас. Отмечу лишь, что Тихановский А.С. почти все манипуляции с объектами файловой системы производит с помощью классов WMI, без помощи классов DirectoryInfo и FileInfo.
Вспомните, что у нас имеется кнопка CheckBox checkHidden, которая должна включать и выключать режим видимости системных или скрытых папок. Обработчик события CheckStateChanged для этой кнопки вы должны были создать ранее. Теперь добавим в него код, который будет переключать режим видимости.
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.