
從圖形狀態切換理解 Parse 與狀態驅動模式面向初學者 | 無代碼純思路目錄先看一個場景什么是 Parse為什么圖形能自動變色一個數字裝下很多個狀態為什么不用一個狀態屬性而是散落的 9 個三個轉換器各管一攤從頭到尾走一遍總結先看一個場景想象你在操作一個檢測軟件畫布上有很多矩形圖形。當發生以下情況時圖形外觀會變化鼠標點擊圖形 → 邊框變虛線檢測結果 OK → 背景變綠色檢測結果 NG → 背景變紅色正在掃描 → 背景變橙色既沒選中也沒狀態 → 默認實線邊框問題來了程序怎么知道一個圖形當前是什么狀態然后自動切換顏色什么是 ParseParse 讀懂一份數據翻譯成另一種格式。生活類比原始數據翻譯后看體溫計水銀柱“38.5 度”看紅綠燈亮紅燈“停”讀成績單“張三 數學 85”{名字:“張三”, 科目:“數學”, 成績:85}程序里的 Parse 完全一樣輸入一堆碎片信息 → 輸出一個有意義的整體為什么圖形能自動變色第一步ViewModel 告訴外界我有什么屬性每個圖形對象對外暴露一組屬性全是是/否這個圖形被選中了嗎 → 是 / 否 這個圖形被鼠標懸停了嗎 → 是 / 否 這個圖形正在被掃描嗎 → 是 / 否 這個圖形掃描完了嗎 → 是 / 否 這個圖形正在重建嗎 → 是 / 否 這個圖形重建完了嗎 → 是 / 否 這個圖形正在檢測嗎 → 是 / 否 這個圖形檢測結果 OK → 是 / 否 這個圖形檢測結果 NG → 是 / 否總共 9 個問題每個答案不是是就是否。第二步WPF 的多路綁定把這些答案打包送出WPF 有一個機制叫MultiBinding多路綁定它能把多個屬性同時、按順序送給一個處理函數MultiBinding 說我把 9 個屬性的值打包成一個數組你按順序拿—— 第一個位置 → 是否選中 第二個位置 → 是否懸停 第三個位置 → 是否掃描 ... 第九個位置 → 是否 NG第三步Parse 函數把是/否轉換成狀態對象收到的就是一堆 true / false比如[true, false, true, false, false, false, false, false, false]Parse 的工作讀懂這些 true/false 分別表示什么把它們合并成一個復合狀態。[true, false, true, ...] ↓ 這個圖形被選中了 正在掃描中第四步轉換器根據狀態決定顏色Parse 輸出的狀態交給不同的轉換器Parse 輸出的狀態 │ ┌────────────────┼────────────────┐ 邊框轉換器 背景轉換器 描邊轉換器 決定線型 決定背景色 決定描邊色每個轉換器做的事情就是查表如果狀態里有NG → 給紅色 如果狀態里有正在檢測 → 給青色 如果狀態里有選中 → 給虛線 如果什么都沒有 → 給實線默認色有優先級NG OK 檢測中 掃描中 懸停 選中 默認。一個數字裝下很多個狀態你會問一個圖形同時選中又正在掃描又結果 NG怎么存用位標記技巧把每個狀態分配一個二進制位選中 → 第 0 位 懸停 → 第 1 位 掃描中 → 第 2 位 檢測中 → 第 5 位 結果 OK → 第 6 位 結果 NG → 第 7 位 ...一個 int 有 32 位足夠裝下所有狀態。一個圖形選中 掃描中 NG → 第 0 位置 1、第 2 位置 1、第 7 位置 1 → 最終存成一個整數查詢時很簡單狀態里有沒有 NG→ 看看第 7 位是不是 1。特殊處理OK 和 NG 互斥一個檢測結果不可能同時 OK 又 NG。所以加一條規則如果傳入OK → 先加上 OK 標記再擦掉 NG 標記 如果傳入NG → 先加上 NG 標記再擦掉 OK 標記后寫入的會覆蓋前一個。基礎語法課堂如果你是初學者下面這些寫法可能會讓你困惑。我們用人話解釋一下。位運算|、|、、~這組符號用來操控位標記狀態。加標記|OR或我有一個狀態 選中第 0 位是 1 我想再加正在掃描 選中 | 正在掃描 結果 選中 正在掃描兩個 1|的作用是只要任意一邊的位是 1結果就是 1。所以適合往上加標記。|是|的簡寫狀態 狀態 | 正在掃描 ← 完整寫法 狀態 | 正在掃描 ← 簡寫效果一樣就像x x 5可以簡寫成x 5。查標記AND與想知道狀態里有沒有NG 狀態 NG → 如果結果不為 0說明有 NG的作用是只有兩邊的位都是 1結果才是 1。狀態 選中 | NG 第 0 位和第 10 位是 1 狀態 NG 非零 → 有 NG 狀態 OK 0 → 沒有 OK擦除標記~配合NOT取反想擦掉狀態里的OK標記 狀態 狀態 (~OK)~把 OK 的二進制位全部翻轉原來 OK 對應位是 1翻轉后變成 0原來別的位是 0翻轉后全是 1。然后用去與一下OK 對應的位會變成 0被擦掉其他位保持不變。OK 0001000000 假設 OK 占第 6 位 ~OK 1110111111 除了第 6 位其他全是 1 狀態 ~OK → OK 對應的位被清 0其他位原樣保留三元表達式條件 ? 是 : 否這是if-else的迷你版if (條件) { 取值A; } else { 取值B; } 等價于條件 ? 取值A : 取值B通常用來做防御防止傳入的值是 null 導致崩潰傳入值可能是 null → 如果是 null用 false 代替 傳入值可能是 abc → 不是 bool也用 false 代替 傳入值 true → 正常使用is bool 變量名模式匹配這個東西同時干了三件事某個值 is bool s第幾步干什么舉例①判斷這個值是不是 bool 類型null 不是 / “abc” 不是 / true 是②如果是把值存到變量 s 里s true③如果否s 不存在整個表達式為 false—變量名沒有含義叫 s、flag、x 都行用完就扔。極簡寫法某個值 is true不需要起變量名直接判斷是不是 true。null 和 false 都會被視為不是 true。WPF MultiBinding 怎么傳參數WPF 會把 XAML 里綁定的屬性按順序打包成數組XAML 寫的順序 第 1 個綁定 → 數組[0] 第 2 個綁定 → 數組[1] 第 3 個綁定 → 數組[2]下標就是綁定的序號。轉換器收到的就是一個object[]里面每個位置對應一個綁定的屬性值。注意東西類型是object而不是bool。因為 WPF 的綁定系統在傳值時不檢查類型什么值都能塞進去null、字符串、數字……都可能。所以轉換器里必須做類型判斷。一句話總結這堆語法符號作用一句話加標記加標記簡寫查標記“看看某一位是不是 1”~取反“除了這一位其他全變” ~擦標記“把某一位清零”? :三元“迷你 if-else”is bool s模式匹配“判斷 取值 防御”數組[下標]取值“第幾個綁定的屬性”為什么不用一個狀態屬性而是散落的 9 個理想的設計是ViewModel 直接暴露一個狀態屬性而不是 9 個散落的 true/false。// 理想 圖形.當前狀態 選中 | 掃描中 | 結果OK // 實際情況 圖形.是否選中 true 圖形.是否掃描中 true 圖形.是否結果OK true ...為什么沒按理想來因為這些 true/false 屬性不只是為 UI 顏色服務的。它們還要被業務邏輯直接讀取如果選中了 → 啟用刪除按鈕 如果正在掃描 → 禁用編輯這些業務判斷直接讀是否選中比查位標記要直觀。所以屬性先以散落的 bool 形式存在后來要給 UI 加自動變色功能時用 MultiBinding 打了個補丁。這是真實項目中常見的歷史選擇——不是最優方案但改動成本高于收益。按長度分組的潛在問題Parse 函數里有一段按傳了多少個屬性做分組判斷的邏輯。這種寫法有一個隱患如果一個圖形只綁了是否選中這一個屬性長度1那么是否選中的狀態會被靜默跳過永遠解析不到。現在沒出 bug純粹因為所有用到這個轉換器的圖形都恰好綁了至少兩個屬性但并沒有任何機制保證這一點。三個轉換器各管一攤轉換器管什么怎么判斷邊框轉換器實線/虛線/無線只看選中和懸停背景轉換器填充色按 NG OK 檢測中 掃描 懸停 優先級描邊轉換器邊框顏色同背景邏輯但用不透明顏色同一個狀態值三個轉換器分別讀自己關心的部分互不干擾。從頭到尾走一遍1. 用戶點擊一個圖形 → 圖形.是否選中 true 2. WPF 檢測到屬性變化 → 把 9 個屬性值打包[true, false, false, ...] 3. Parse 處理 → 讀第一個位置true → 打上選中標記 → 讀其他位置都是 false → 不加標記 → 輸出狀態 選中 4. 邊框轉換器拿到選中 → 查表選中 → 虛線 5. 背景轉換器拿到選中 → 按優先級查表不是 NG不是 OK不是檢測...是選中 → 透明色 6. 描邊轉換器拿到選中 → 選中 → 返回默認描邊色 7. 畫布刷新 → 圖形邊框變虛線用戶看到視覺反饋整個過程無需手寫任何如果 xx 就把顏色設為 yy的代碼全部由轉換器自動處理。總結Parse 讀懂原始數據翻譯成結構化信息。像體溫計把水銀柱翻譯成38.5 度。MultiBinding 把多個屬性同時打包送給一個處理函數。像快遞員一次性取走 9 個包裹。位標記 一個整數裝下多個是/否。每個狀態占一個二進制位加一起就是一個整數。轉換器 查表決策。輸入狀態 → 按優先級查表 → 輸出對應的顏色/線型。散落的 9 個 bool 是歷史選擇。不是最優但改動成本高于收益。整個模式的本質散落的 bool 值數據 ↓ Parse 結構化狀態語義 ↓ Converter 視覺表現顏色/線型數據 → 語義 → 表現三層分離各不越界。