Да, мой код на порядок примитивнее. Я просто хотел выполнить то, что описано в MSDN, но видно здесь много подводных камней.
Я изучил Ваш код.
Вижу была задумка сделать управление несколькими окнами (класс PanelManager), но потом (метод TogglePanel) все было свернуто до одного окна. Хотя возможно в этом есть смысл: один плагин - одно окно.
Но самая большая прелесть - это, конечно, класс PanelFrame : IVisEventProc.
Я вижу, что была проделана большая работа и, возможно, множество экспериментов. У меня есть несколько вопросов, буду очень благодарен, если Вы мне объясните некоторую магию этого кода.
1)
Код:
private const string AddonWindowMergeId = "29dc9325-911a-4ad1-8594-d775e374c180";
....
_visioWindow = visioParentWindow.Windows.Add(
_form.Text,
(int)VisWindowStates.visWSDockedRight | (int)VisWindowStates.visWSAnchorMerged | (int)VisWindowStates.visWSVisible,
VisWinTypes.visAnchorBarAddon,
0,
0,
300,
300,
AddonWindowMergeId,
string.Empty,
0);
Что за AddonWindowMergeId ? Для чего он нужен? В документации по Visio сказано, что это : Merge ID of the window.
То есть ID объединенного окна. Но когда мы добавляем окно в словарь ( _panelFrames.Add(window.ID, panelFrame ); ) я вижу в отладчике просто ID окна - простые цифры, не GUID.
2)
Код:
SetWindowLong(_form.Handle, GWL_EXSTYLE, WS_EX_COMPOSITED);
Этот стиль окна определяет, что окно будет перезаписываться снизу-вверх. То есть сначала родительское окно (нижнее), потом дочернее (верхнее). В MSDN об этом не было сказано. Без этого не работало?
3)
Код:
private static void JiggleWindow(
IntPtr handle)
{
var lpRect = new RECT();
GetWindowRect(handle, ref lpRect);
var l = lpRect.left;
var T = lpRect.top;
var w = lpRect.right - lpRect.left;
var h = lpRect.bottom - lpRect.top;
const int flags = SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOZORDER;
SetWindowPos(handle, new IntPtr(0), l, T, w, h + 1, flags);
SetWindowPos(handle, new IntPtr(0), l, T, w, h, flags);
}
Для чего сначала считывается позиция окна, а потом устанавливается? Для того, чтобы прописать флаги?
SWP_NOCOPYBITS - не перерисовывать содержимое клиентской области.
Область родительского окна закрыта дочерним. Возможно это нужно для улучшения производительности?
SWP_NOMOVE | SWP_NOZORDER - определяют не изменять Z порядок и положения окна.
Получается, что мы передаем в окно только РАЗМЕР, то есть меняем размер окна?
4)
Код:
SetWindowPos(handle, new IntPtr(0), l, T, w, h + 1, flags);
SetWindowPos(handle, new IntPtr(0), l, T, w, h, flags);
Для чего нужно было менять размер окна? Оно не перерисовывалось?
5) Событие закрытие окна отлавливается 2-мя способами
1 - Привязкой к событию закрытия окна : _visioWindow.BeforeWindowClosed += OnBeforeWindowClosed;
2 - В отлавливании события закрытия окна в object IVisEventProc.VisEventProc
Для чего? BeforeWindowClosed не всегда отрабатывало?
6)
Код:
if (_visioWindow != null && _form != null)
{
_form.Hide();
SetWindowLong(_form.Handle, GWL_STYLE, WS_OVERLAPPED);
SetParent(_form.Handle, (IntPtr)0);
_visioWindow.Close();
_visioWindow = null;
}
if (_form != null)
{
_form.Close();
_form.Dispose();
_form = null;
}
Я вижу, что сначала убирается стиль дочернего окна в форме (SetWindowLong(_form.Handle, GWL_STYLE, WS_OVERLAPPED);)
Потом убирается указатель на родительское окно ( SetParent(_form.Handle, (IntPtr)0); )
И только после этого закрывается родительское окно, а затем форма.
Получается - закрытие родительского окна не приводит к закрытию окна дочерней формы?