Skip to content

浮動預覽視窗機制 ​

本頁包含浮動預覽為什麼不是工具視窗、擺放位置、尺寸記在哪、釘住與搬動、外觀與進出場,以及 停靠的工具窗。什麼時候收、鍵盤與滑鼠行為見預覽互動。

為什麼不是工具視窗 ​

視窗掛在編輯器自己的空間保留管理員上,也就是 IntelliSense 清單與提示視窗 用的那一套機制,並且排在內建的 completion 之後。自訂 Agent 取得前序視窗已經 保留的區域,再用明確矩形定位自己的 WPF Popup:

  • 位置可預測:建議清單仍由 reservation geometry 自動量得,但上下的優先序、 文件邊界與遲滯由 PreviewPlacementEngine 的純規則決定。
  • 點進去不會關掉清單:焦點落在這種視窗裡時,編輯器仍然算「持有焦點」, 所以可以用滑鼠把 CREATE TABLE 整段拉選起來,建議清單不會消失。
  • 跟著編輯器走:切到別的分頁或版面暫時放不下時,Agent 只把 Popup 藏起來並回報空幾何 (Geometry.Empty);回報 null 會讓平台移除 Agent,等於把「暫時看不見」當成使用者 不要了。錨點捲出畫面時同樣先藏,再交給生命週期決定收不收。SSMS 視窗搬動時當下就照 編輯器的位移平移 Popup(NativeScreen.MoveWindowOf),再排一次完整重排:Popup 是自己的 頂層視窗,只等重排的那一版落後一兩格,像被橡皮筋拖著。

不能只換成獨立 Window 或一般 Popup:那兩者不在編輯器的聚合焦點裡,點進內容 就會讓 completion 認為編輯器失焦。自訂 Agent 保留平台的生命週期,只有定位改由 本擴充負責。要跨分頁留著、放到別的螢幕的另有停靠的工具窗。

擺放位置 ​

只有一種擺法:錨點的下方,放不下才到上方;尚未手動調寬時從錨點延伸到編輯器右側。 為什麼不再提供貼在清單側邊的設定見設定的「刻意不是設定的東西」。 同一次顯示會保留上一個仍然可行的方向,避免提示多一個像素或 DPI 捨入時反覆翻面。 所有候選都逐一檢查分離的保留區,不會把兩個遠離的浮窗粗略合成一個巨大外框。

蓋住整個錨點的保留區不算障礙。 建議清單開著時,平台會連錨點所在的一整行一起保留; 它表達的是「錨點在這裡」,不是浮窗。只排除完全蓋住錨點的那一種:改用相交會把緊貼 錨點下緣、DPI 捨入後重疊一兩個像素的建議清單也一起排掉,那才是真正必須讓開的東西。

打開 sqlAssist.diagnostics.verboseLogging 之後,每次顯示都會在記錄檔留下一行落點資訊 (方向或釘住、視窗與錨點的螢幕像素矩形、文件可用範圍、每一個保留區的矩形、記住的尺寸)。

錨點靠右而放不下正常寬度時,整個矩形只往左平移到文件界內,不縮成細條,也不讓 Popup 自己翻面。垂直可用範圍來自完整查詢文件欄與目前螢幕工作區的交集,不是 SQL 文字 Viewport;因此開啟 SELECT 結果只代表預覽可以覆蓋結果區,不會把記住的高度壓回 180。 文件欄只接受左右界與編輯器吻合的 WPF/Win32 最近父容器;辨識不到時保守退回 文字 Viewport,不拿整個 SSMS 主視窗猜測,以免蓋住底部工具窗或另一個分割文件。

比對邊界用的是含裝飾邊的編輯器控制項(WPF 樹上實作 IWpfTextViewHost 的那一層), 不是文字 Viewport。Viewport 的左界不含中斷點欄、行號欄與變更欄,右界不含捲軸, 兩邊加起來就超過任何合理的容忍值,於是每一個祖先都被判成不是同一欄——文件欄永遠 找不到,而症狀不是報錯,是「查詢一有結果,預覽的底就卡在文字區底部」。認不出那一層 時基準才退回 Viewport,容忍值也跟著放到整條裝飾邊之外。落點記錄的「底界來源」一欄: wpf/win32 是找到了同欄父容器,none/* 則是沒找到而停在編輯器底部。

尺寸記在哪 ​

錨在名稱上的預覽共用一份尺寸(Settings/PreviewWindowState):寬度是「延伸到編輯器 右側」這個狀態或一個固定值,加上高度。存 VS 的 WritableSettingsStore,沿用舊版上下擺放 的鍵名,升級時刪掉側邊與最早一版不分擺放的舊鍵。

  • 只有遠離錨點那一側的右角有握把。 左緣跟著錨點、靠錨點那一緣跟著錨點行,使用者能 決定的只有寬與高;以前左角也有握把,放開之後定位把左緣拉回錨點,怎麼拖都沒用。
  • 真的拖過的軸照畫面上的值記,被版面壓矮的那一軸也一樣。以前被壓縮過的軸一律不記, 結果下方空間不夠時怎麼拉高度,放開都彈回原樣。
  • 位移不到一個握把邊長(16 DIP)的軸當作沒拖:角落握把一定同時動到兩軸,只想拉寬的 人也會帶進幾個像素的垂直位移;寫回去的話被壓矮的高度就成了記住的高度,自動寬度也會 換成固定值再也回不去。代價是不到 16 DIP 的微調會彈回。
  • 版面暫時放不下而縮的是這一次的矩形,不寫回記住的尺寸。
  • 雙擊握把回到預設:自動寬度、預設高度。

釘住的視窗大小不讀也不寫這一份:那是擺在某個地方的一扇窗,拖一扇窄窗就讓之後每一次 預覽都變窄的話,使用者分不出是哪一次拖出來的。

釘住與搬動 ​

**釘住的是位置。**釘住之後那扇窗就是這個編輯器的預覽出現的地方,不論內容由誰打開:窗擺在哪 只看釘不釘住,清單借用時也留在原處。內容怎麼換見預覽互動。按圖釘,或直接拖抬頭(沒釘住的 先釘住:錨在名稱上的放開又會被拉回錨點)。釘住的那一刻以眼前的矩形為起點,範圍也當場換成下面那一條,否則沒釘住就拖 的第一次仍被關在查詢視窗裡。

  • 矩形以編輯器左上角為基準記成 DIP:捲動、打字都不動它;SSMS 視窗搬動、分割線拉動時 跟著編輯器走。
  • 範圍是編輯器所在的整個 SSMS 視窗(含物件總管與底部工具窗),收進螢幕工作區;錨在名稱上 的才限在文件欄,不蓋住使用者沒叫它蓋的東西。再往外交給工具窗: Popup 屬於編輯器,跨出 SSMS 視窗的那一塊在編輯器被遮住時會懸在半空。
  • 視窗變小時先平移、平移不夠才縮小,收進範圍(PreviewDragEngine.Contain)。顯示的 矩形不寫回,視窗回到原本大小時預覽也回到原處。
  • 不讓開建議清單與提示;握把在下緣兩角,抬頭負責搬。
  • 放開圖釘回到錨點上下,從記住的尺寸重算。

搬動與改尺寸是同一個 PreviewDragEngine:每一步都是「按下瞬間凍結的矩形+游標總位移」, 收在同一個範圍裡;錨在名稱上時範圍再扣掉四周的浮窗,放開後定位才會落在同一個地方。

外觀與進出場 ​

外殼(PreviewSurface)與內容(SqlStructurePanel)分開:內容與工具窗共用,圓角、柔影、 握把、抬頭的三顆工具與進出場只屬於浮動預覽。與通知島同一種浮層(SqlAssistChrome.Surfaces):圓角 FloatingSurfaceRadius、柔影只掛在 底色層並點陣快取,高對比不畫影子。底色維持不透明,不用通知島的玻璃——一百多列的資料格 疊在透出來的 SQL 上讀不清楚。

Popup 以外畫不出東西,所以外圈留一圈透明的陰影邊(ShadowMargin),影子在自己的矩形 裡長。reservation 與可點擊區仍是整個矩形;這一圈同時就是與錨點、建議清單的間距,定位的 LayoutGap 因此是 0,否則是兩份間距。

進出場與通知島同一套語言(UI/SurfaceMotion、UI/SurfaceCapsule):錨點下方的圓點先長成 膠囊,再攤開——寬先、高隨後落下,圓角從全圓收成表面圓角——內容晚 60 ms 才淡入並從 0.96 放大。表面依最終尺寸排好版,外形只由裁切露出,資料格不重排。舊版讓內容跟著裁切一路露出, 外形還在長的時候整片資料格像從門縫裡擠出來。

**內容還沒到就停在膠囊。**膠囊寫著名稱、轉著與通知島同一顆進度圈,停多久由 Core/Preview/PreviewReveal 決定:寬限內到齊的看不到等待(快取命中是常態,一律先停等於人為 變慢),進度圈浮現後至少留一段免得一閃而過,到上限還沒到就照樣攤開,交給抬頭的「載入中」。 第二層的欄位到了就算到齊。先攤開一片只有標題的表面的那一版,看起來像這個物件什麼都沒有。

換內容有三種動法:跟著清單選取換的不動,方向鍵連按時每一格都動只會拖慢眼睛;釘住的窗 原地換,新內容浮上來;換到另一個名稱旁邊時舊位置縮回寫著新名稱的膠囊,收完才換上內容、 在新位置長出來——直接跳位的那一版,眼睛追不上是同一扇窗換了地方還是又開了一扇。

收起時內容先淡出、外形縮回膠囊、整個表面同時淡掉;清單上路過關鍵字而暫時收起時直接收, 否則每按一次方向鍵都有一段動畫。縮回期間內容還掛在舊的承載視窗上,而內容只有一份,新 Agent 掛上之前必須先 CompleteExit。

顯示時不會主動搶焦點,游標留在編輯器裡,可以繼續打字;滑鼠滾輪不需要焦點 就能捲動,要拉選文字時點一下才把焦點交出去。

WPF 的 Popup 被點時不啟用自己的程式。切到別的程式之後再點回預覽,SSMS 仍在背景, 鍵盤焦點進不去:搜尋框點不進、指令碼拉選不起來、Esc 送到別的程式,只有分頁、資料格 與捲軸這些純滑鼠的操作照常動。所以每一次按下都先把編輯器所在的框架帶回前景 (SsmsWindows.ActivateFrameOf),再照常處理這一次按下。框架由 SsmsWindows.WindowOf 沿 HWND 找;用 Window.GetWindow 的第一版對編輯器拿到 null,什麼都沒啟用,症狀跟沒修一樣。

停靠的工具窗 ​

抬頭的「移到工具窗」把眼前這一份交給 SqlStructureToolWindow,浮動預覽跟著收起。浮動預覽屬於 一個編輯器,換分頁就藏起來;要一直開著、在另一個查詢視窗照著寫、放到另一台螢幕的,交給殼層 的停靠系統。內容與分層載入同一份(SqlStructurePanel、SqlStructurePresenter),沒有外殼; 搜尋框不經 ShellKeyCapture,殼層照工具窗自己派送按鍵。只有一扇,再移一次就換內容。

繼承 SqlToolWindowPane:排到本輪輸入之後才顯示,再換內容,焦點落在搜尋框。

尚未確認 ​

  • 圓角下的角落握把仍拖得到、陰影邊點下去不會被當成點到後方的編輯器(100%/150%/200% DPI)。
  • 預覽開著時停在別的名稱上,滑鼠停留提示出現與消失都不讓預覽跳位。
  • 沒釘住就拖抬頭能拖出查詢視窗;抬頭按鈕是手形、其餘是搬動游標。
  • 釘住後清單借用時窗留在原處、拖得動,還回去時仍在拖到的位置。
  • 釘住後拖抬頭搬動(含拖到物件總管上)、下緣兩角改尺寸,捲動與切分頁回來都留在原處; 150%/200% DPI 下不漂移。
  • 拖著 SSMS 視窗走時預覽同步跟隨,跨不同 DPI 的螢幕放開後不錯位。
  • 冷快取時膠囊等待再攤開的節奏;Ctrl+F12 連續換名稱時縮回再長出不卡、不閃舊內容。
  • 移到工具窗之後換分頁、拖到別的螢幕、換介面語言,內容都還在。
  • 下方空間不足時拉高度,放開後停在拉到的高度,下一次預覽沿用。
  • 長出動畫在大尺寸(整個編輯器寬、上千 DIP 高)與遠端桌面下不掉格。

以 Apache-2.0 授權條款發布 · 專為 SSMS 22 設計