Skip to content

浮動預覽的操作與效能 ​

本頁處理什麼時候收、操作、按需載入與縮放;視窗殼層、擺放與外觀見浮動預覽視窗。

什麼時候收 ​

規則只有一條,寫在 Core/Preview/PreviewLifecycle:預覽活到使用者的意圖離開它為止, 焦點變化永遠不算。 打開的方式決定意圖:

狀態怎麼打開什麼時候收
瀏覽清單上 → 或停夠久清單結束(挑選完成或關閉)或 ←
指名Ctrl+F12、Ctrl+點擊、提示連結、工具選單游標離開那個名稱、那個名稱被改、捲出畫面
釘住按抬頭的圖釘或拖抬頭只有 Esc 或關閉鈕

三種都在 Esc 與關閉鈕時收。釘住的是位置,不擋任何來源:釘住之後指名打開的換掉釘住的 那一份、仍然釘著;清單上展開的借用那扇窗,清單結束或 ← 就還回去(PreviewOutcome.ReturnToPin), 借用期間路過沒有結構的項目時顯示釘住的那一份,窗不收。以前釘住只擋「停夠久自動展開」,→ 與 Ctrl+F12 卻默默解除釘住、跳回錨點:在清單上看起來是預覽壞了,按了 Ctrl+F12 又像圖釘沒用。切到別的程式或分頁只是暫時藏起來,回來照原樣出現。以前的 收起散在清單事件、失焦後檢查鍵盤焦點與平台移除三處,看的是那一瞬間焦點在誰身上:點過 預覽與沒點過的切到別的程式收法不同,指名打開的點別行也不收。

錨點捲出畫面則分開看:指名的收,捲走是自己把視線移開那個名稱,跟游標離開同一回事—— 只藏起來的那一版,捲回去時預覽又自己冒出來,使用者早就不在看它了。清單上展開的不收, 清單自己也跟著錨點藏起來、捲回去一起回來。釘住的不再錨在名稱上,捲動不動它。

  • 游標規則在本輪命令結束後判斷,文字變更也要排一次(游標跟著編輯位移時平台不發游標事件)。 名稱前後緣都算在名稱上。
  • 一個編輯器只有一個預覽,新的要求一律換掉舊的內容。放開圖釘回到指名,以當下的名稱文字 重新起算;借用中放開時窗回到清單旁邊繼續跟著選取,釘住的那一份跟著放掉。
  • 清單選取(_selection)與畫面(SqlStructurePresenter.Subject)分開記:清單開著時畫面上 可能是指名或釘住的另一個物件,在清單上換選取不能動到它的查詢與節流。
  • 預覽攤開某個名稱時,同一個名稱上不出滑鼠停留提示。提示排在預覽前面的保留區,錨點沒動 而提示開著時預覽留在原地,不被它推開。

操作 ​

按鍵/動作行為
Ctrl+F12顯示游標處物件的完整結構,不受自動預覽設定影響
Ctrl+點擊物件名稱同 Ctrl+F12,位置是點到的那個名稱
→建議清單開著、選到的項目有結構時展開預覽;其餘照常右移游標
↑ ↓展開狀態下跟著選取換內容;選到沒有結構的項目時視窗先收起,移回有結構的再出現
←畫面上有預覽時收合;其餘照常左移游標
Esc、關閉鈕收掉預覽;清單開著時先關清單,只有瀏覽狀態跟著收
圖釘釘住或放開;放開回到錨點上下
移到工具窗眼前這一份交給停靠的工具窗,浮動預覽收起,見預覽視窗
拖曳抬頭搬到別處;沒釘住的先釘住
Tab Enter挑選完成,預覽跟著關
滑鼠拉選 + Ctrl+C複製選取的內容
分頁列右側搜尋、換行開關、複製(有選取複製選取,沒有就是完整指令碼),不受鍵盤焦點影響
搜尋框資料格只留符合的列並標出命中,指令碼標出每一處;分頁標籤換成命中數
搜尋框裡 Enter/Shift+Enter指令碼分頁走到下一處/上一處
搜尋框裡 Esc有字時先清字,第二次才關預覽
右鍵複製選取內容/複製整個表格/複製完整指令碼
角落握把錨在名稱上時只有遠離錨點那側的右角,釘住時是下緣兩角;雙擊回到預設尺寸

指令碼分頁是共用的 SqlReadOnlyViewer(與 SQL Search/Memory 的預覽同一份),著色用 本擴充自己的詞法分析器,字型與顏色向目前查詢視窗的分類外觀對應表借;更新與快取失效見 主題連動。

搜尋是字面比對、不分大小寫,走 TextMatcher;命中的配色與兩級見命中高亮。 資料格用篩選不用導覽:一百多欄的表只標出命中而不篩,照樣要一路捲下去找;指令碼反過來, 篩掉幾行就讀不懂,所以是高亮加一處一處走。比對只看看得見的欄,讀法與複製同一份 (SqlDataGridText.CreateSearchIndex)。收起預覽就清掉搜尋字:下一次打開是另一件事。

搜尋框是編輯器裡的 Popup,Backspace、方向鍵、Enter 會先被殼層解析成編輯器命令, 所以它握著鍵盤的期間由 ShellKeyCapture 把那些命令交還給它,見按鍵交還。

這裡刻意不內嵌真正的編輯器:內嵌編輯器雖然能拿到免費的著色, 但它會把鍵盤焦點搬進另一個呈現來源,編輯器因此判定自己失去聚合焦點, 整個浮動視窗會在使用者點下去的那一刻被平台收掉——同一個視窗裡的資料格分頁 完全沒有這個問題,差別就在這裡。

複製一律走明確的處理常式與分頁列上的按鈕,不依賴 ApplicationCommands.Copy 的繞送: 浮動視窗是自己的一個承載視窗,拿不到鍵盤焦點,命令繞送不到就會變成 「選得起來但複製不了」。資料格分頁以儲存格為選取單位,只複製可見選取;不連續選取的 洞留空,不夾帶未選的格子。列依排序與篩選後的檢視、欄依拖曳後的順序輸出;多行或含 定位字元的內容以 TSV 引號保留儲存格邊界,純文字讀取與空欄判斷共用同一份實作。

Ctrl+C 也因為同一個理由收不到,所以改由查詢視窗那一端的命令處理常式轉過來: 編輯器自己沒有選取、而預覽裡有選取時,這個命令就交給預覽。 選取的顏色則開了非作用中高亮,否則沒有焦點的視窗裡選起來是看不見的。

指令碼是可以直接執行的:主索引鍵寫進 CREATE TABLE 的條件約束, 唯一條件約束寫成 ALTER TABLE,計算欄位寫成 AS 運算式;資料表型別則是 CREATE TYPE ... AS TABLE。

不卡頓的做法 ​

  • 視窗預先建好:建議清單第一次開啟之後,以 ApplicationIdle 優先權在背景 把整棵 WPF 樹建起來——那是兩次按鍵之間 UI 執行緒真的沒事做的時候。
  • 沒展開就不做事:方向鍵掃過二十項時,預覽只記下選到誰,不畫也不查。
  • 由便宜到昂貴(SqlStructurePresenter,工具窗共用):第四層快取命中就直接畫完; 只有第二層命中就先畫欄位、索引與外來鍵稍後補上;兩層都沒有才先畫標題並啟動節流計時器。
  • 節流:換選取後預設等 220 毫秒才真的查資料庫,按著方向鍵一路往下時 中途的每一項都不會送出查詢。
  • 只填看得見的分頁:七個分頁一起填等於每換一個物件就多六次版面計算, 切過去時再填。
  • 搜尋每打一個字只比字串:每張資料格看得見的欄的文字在第一次搜尋時讀一次(一個物件 一次),之後每個字只比對字串;比出來的那組列同時給列篩選與分頁數字,不比兩次。先換篩選 再換比對器,快要丟掉的格子不白畫一次;指令碼要整份重新著色,只在它是眼前那一頁時重排, 其餘等切過去再排。逐格反射、而且篩選與數命中各比一遍的那一版,一百多欄的表每打一個字就卡一下。
  • 同一次換選取只重畫一次:平台每換一個項目會從方向鍵命令、說明 callback 與 ItemsUpdated 分別通知一次。這三條都只把「選取可能換人了」記下來並去背景對帳, 不碰畫面也不動查詢;要不要換內容由對帳結果決定,解析出同一個物件就什麼都不做。 任何一條先把畫面清掉,另外兩條就會讓同一個物件再重畫 一次——症狀是每按一次方向鍵閃一下,而且剛送出的查詢會被取消再送一次。
  • 昂貴的量測只在會變的時候量:DPI 轉換矩陣一輪定位只取一次;查詢文件欄的底界 要爬 WPF 祖先樹再走一段 Win32 迴圈,改用編輯器矩形當鍵快取,捲動與打字都不重算。 落點診斷那一行也先看設定再組字串——它在每一次捲動與每一個按鍵上都會走到。

分頁與欄的收合 ​

分頁的可見性、資料列與「要不要等第四層」寫在同一筆宣告裡(GridTab)。分散成 三段判斷的症狀是新增分頁時漏掉其中一段——漏可見性是空分頁留在畫面上,漏填入是 切過去一片空白,兩者都不會編譯失敗。數量與資料列是兩個委派:可見性每換一個物件 都要問,資料列只有真的切過去才建。

**整欄都是空的欄也收掉。**沒有計算資料行、沒有掛說明、沒有篩選索引時,那一欄仍 佔著標題與內距而一個字都沒有——與旗標收成一欄膠囊同一條理由,差別只在這次是整欄。 判斷在填入之後做一次,成本落在真的切過去的那個分頁,屬性只解析一次而不是逐格反射; 讀不出繫結路徑時一律保留整欄,因為「查到了卻不見了」比多一個空欄糟。收起來的欄 也不進剪貼簿。

自由文字欄(說明、運算式、篩選、條件約束定義)不能讓一段兩百字的說明把後面的欄 推出視窗外。每張表最長的那一欄吃剩餘寬度(GridColumn.Fill,欄位分頁是說明),其餘 設寬度上限;只設上限的那一版在寬視窗裡照樣截斷說明,而右邊明明還空著。還是讀不完時 開「換行」:只換自由文字欄的儲存格樣板與列高,名稱與型別不折行,指令碼一起換行; 不重建資料格,選取與捲動位置都留著。

拖曳為什麼不用一般的做法 ​

Thumb 回報的是相對移動中父代的逐幀增量;直接累加會形成回授。拖曳開始時因此 凍結原始 Rect、把手與限制範圍,每一步都用游標的螢幕實體像素算「起始 Rect + 相對 起點總位移」(Core/Preview/PreviewDragEngine)。原生游標取不到時改用 WPF 的滑鼠位置 換到螢幕,一樣是絕對位置,與元素自己有沒有在動無關。抬頭的搬動走同一條路,只多一道 系統拖曳門檻:一般的點擊不能被當成搬動,搬動會順便釘住。

角落握把固定對角:下方落點的右下角固定 Left 與 Top,上方落點的右上角固定 Bottom, 所以縮小後仍能往有空間的方向拉回。拖曳期間不重新定位,reservation stack 只收到同一個 明確 Rect。滑鼠事件合併到每個 Render frame 一次;取消拖曳會還原且不保存。尺寸以 DIP 保存,定位運算與平台一致使用螢幕實體像素,只在 Adapter 邊界做一次 DPI 轉換。放開時記 哪一軸見預覽視窗。

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