Форум пользователей Visio http://visio.getbb.ru/ |
|
Окна Ancor в Visio http://visio.getbb.ru/viewtopic.php?f=6&t=1623 |
Страница 1 из 1 |
Автор: | vin [ 15 сен 2020, 18:58 ] |
Заголовок сообщения: | Окна Ancor в Visio |
Делаю Add-In на C#. Нужно сделать окно, которое ведет себя так же как окна Visio - докается к сторонам внутри окна, имеет возможность скрываться и т.д. Такие возможности описаны в MSDN: https://docs.microsoft.com/en-us/previous-versions/office/developer/office2000/aa140261(v=office.10)?redirectedfrom=MSDN и современный вариант, который содержит ошибку: https://docs.microsoft.com/en-us/office/vba/api/visio.windows.add (В современном варианте немного перепутали: в функцию поиска окна нужно искать заголовок формы frmMain). Но не в этом суть. Вот код: Сначала об]являем функции WinAPI, которые будем использовать Код: public static class WinAPI { [DllImport("user32.dll", SetLastError = true)] public static extern IntPtr SetParent(IntPtr hWndChild, int hWndNewParent); [DllImport("user32.dll", SetLastError = true)] public static extern IntPtr SetWindowLongPtrA(IntPtr hwnd, int nIndex, int dwNewLong); а затем используем Код: public void Command1(object sender) { const int GWL_STYLE = (-16); const int WS_CHILD = 0x40000000; const int WS_VISIBLE = 0x10000000; frm = new Form1(sender); var vsoWindow = this.Application.ActiveWindow.Windows.Add( bstrCaption: "My New Window", nFlags : Visio.VisWindowStates.visWSVisible | Visio.VisWindowStates.visWSDockedRight, nType : Visio.VisWinTypes.visAnchorBarAddon, nWidth : frm.Width, nHeight : frm.Height); var s1 = WinAPI.SetWindowLongPtrA(frm.Handle, GWL_STYLE, WS_CHILD | WS_VISIBLE); var s2 = WinAPI.SetParent(frm.Handle, vsoWindow.WindowHandle32); frm.Top = 0; frm.Left = 0; frm.Show(); 1) Я создаю пустое окно с возможностью докаться, и докаю его вправо: var vsoWindow = this.Application.ActiveWindow.Windows.Add( bstrCaption: "My New Window", nFlags : Visio.VisWindowStates.visWSVisible | Visio.VisWindowStates.visWSDockedRight, nType : Visio.VisWinTypes.visAnchorBarAddon, nWidth : frm.Width, nHeight : frm.Height); 2) я создаю форму (на которую накидал button) frm = new Form1(sender); 3) Я объявляю стиль этой формы как дочерний и делаю ее видимой: var s1 = WinAPI.SetWindowLongPtrA(frm.Handle, GWL_STYLE, WS_CHILD | WS_VISIBLE); 4) Объявляю пустое окно родительским для этой формы var s2 = WinAPI.SetParent(frm.Handle, vsoWindow.WindowHandle32); 5) frm.Top = 0; frm.Left = 0; frm.Show(); Это уже от безысходности - пытаюсь показать окно. Но оно не показывается. В чем ошибка? |
Автор: | nbelyh [ 15 сен 2020, 22:03 ] |
Заголовок сообщения: | Re: Окна Ancor в Visio |
Не очень понятно, в чем беда - в проекте же окно галочкой добавляется? Зачем снова все делать руками? Вот попробовал записать видео: https://youtu.be/X1gcBOeI84w Если не поможет, можно подробности? |
Автор: | Гость [ 16 сен 2020, 14:19 ] |
Заголовок сообщения: | Re: Окна Ancor в Visio |
Да, мой код на порядок примитивнее. Я просто хотел выполнить то, что описано в 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); ) И только после этого закрывается родительское окно, а затем форма. Получается - закрытие родительского окна не приводит к закрытию окна дочерней формы? |
Автор: | nbelyh [ 16 сен 2020, 14:52 ] |
Заголовок сообщения: | Re: Окна Ancor в Visio |
О, круто ты реально полез в код ![]() ![]() 1. MergeID - для случая нескольких окон. Чтобы окно не мержилось с окнами Visio в один таб, а вставало в отдельный фрейм. Еще например если создается два окна с одним и тем же MergeID, чтобы можно было их поставить в один таб. По этому слову ("MergeID") на VisGuy гуглится объяснение, также на этом форуме должен быть топик. Но по сути это поведение для докинга (вставать в один таб с другими или нет) ![]() 2. Это добавлено для того чтобы избавиться от мерцания при перерисовке. Объяснение тут: https://stackoverflow.com/questions/261 ... ls/2613272 3, 4. Эта безумная фигня с изменением размера на 1 пиксель, а потом назад да, для форсирования перерисовки (закрывает баг в одной из версий Visio). Ссылку на баг и обсуждение сходу не нашел, найду - добавлю. Скорее всего на visguy и на microsoft connect (лет 5 назад). Redraw или Invalidate не помогало, только такой вот ресайз на 1 пиксель сработал. Надо бы поставить для какаой конкретно версии Visio проблема, кажется 2013 и 2016. 5. Окно можно закрыть нажатием маленький на крестик (на панели), нажатием на кнопку. Также можно закрыть документ целиком. Там есть 2 случая - закрывается панель, и закрывается вся диаграмма (файл). В общем надо учитывать, что может быть открыто несколько файлов диаграмм одновременно. Каждый файл будет иметь свою "панель", и в результате их может быть много (поэтому PanelManger) Панель не одна на Visio, а одна на каждый открытый документ ("одна на все приложение" - в Visio такого нет, в отличие от других программ офиса) Нотификация важна, чтобы перерисовать "нажатость" кнопки на ленте например. Также состояние кнопки надо обновлять при переключении на другое окно (файл) 6. Здесь я уже и сам не вспомню почему так. Вроде бы Visio падал, если не закрыть сначала дочернее. Но точно не помню. Да если все заработает - с тебя ![]() |
Автор: | vin [ 17 сен 2020, 11:28 ] |
Заголовок сообщения: | Re: Окна Ancor в Visio |
nbelyh Спасибо ОГРОМНОЕ за Ваш код и пояснения к нему. Все заработало. Если меня что-то будет не устраивать, я по-крайней мере. вижу путь для развития. Я когда-то на VBA и ShapeSheet сделал несколько фигур с множеством текстовых полей. Поля можно включать\отключать через контекстное меню, а так же двигать с помощью управляющих ручек. При щелчке мышью открывается редактор текста указанного поля. Это удобно, когда рисуешь схему, и нужен какой-нибудь коммутатор с несколькими портами. Но добавление такого поля работа очень кропотливая. Нужно создавать все новые фигуры, а так же добавлять поля к ранее созданным. Поэтому хочу решить этот вопрос с помощью плагина. |
Страница 1 из 1 | Часовой пояс: UTC + 3 часа [ Летнее время ] |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |