免费国产精品自在自线-91精品国产色综合久久久浪潮-99热久久免费频精品-国产精品国模在线观看-久久亚洲国产精品成人?V秋霞-久久国产一级A片免费播放-亚洲国产欧洲综合97久久-久久国产白嫩美女呻吟高潮

ARTICLE DETAIL

資訊詳情

深耕商務(wù)建站與企業(yè)官網(wǎng)運(yùn)營的一線實(shí)戰(zhàn)洞察。

WPF界面框架分層實(shí)踐:主題Token、MVVM與換膚避坑

WPF界面框架分層實(shí)踐:主題Token、MVVM與換膚避坑 簡介面向 WPF 桌面應(yīng)用開發(fā)者的一套現(xiàn)代化界面框架源碼與示例適合希望擺脫默認(rèn)控件外觀、快速搭建統(tǒng)一視覺風(fēng)格的中級(jí)開發(fā)者參考也可作為團(tuán)隊(duì) UI 規(guī)范與主題定制的基礎(chǔ)。壓縮包約 1.84MB共 336 個(gè)文件以 143 個(gè) C# 源碼與 115 個(gè) XAML 界面文件為主體另含 15 個(gè) csproj 工程文件、圖標(biāo)與圖片素材、Visual Studio 項(xiàng)目模板及少量說明文檔覆蓋控件實(shí)現(xiàn)、窗口外殼、主題資源到可復(fù)用模板的完整鏈路。目前已有 6464 人學(xué)習(xí)下載。內(nèi)容圍繞現(xiàn)代化窗口、菜單、對(duì)話框與過渡動(dòng)畫控件展開涉及主題外觀管理與系統(tǒng)版本適配等模塊可據(jù)此理解樣式模板、資源字典與 MVVM 在真實(shí)項(xiàng)目中的組織方式并直接改造為自己的應(yīng)用外殼。1. 一個(gè)漂亮的 WPF 界面框架漂亮之外到底解決什么問題上個(gè)月幫一個(gè)內(nèi)部工具做收尾功能全跑通了評(píng)審時(shí)被一句話打回來這套 WPF 界面看著像十年前的。真正動(dòng)手改才發(fā)現(xiàn)難點(diǎn)不在畫得好看而在主色散落在二十多個(gè) XAML 里、按鈕存在三套模板、每個(gè)窗口的標(biāo)題欄各寫各的。這份 WPF 界面框架源碼包就是把這堆散件整理成三層主題 Token、控件模板、窗口外殼再配一套 MVVM 骨架和若干示例頁。它主要解決兩件具體的事改一處顏色不用翻遍工程新頁面照著示例拼就能交付。適合正在用 WPF 做桌面端、要把界面從「能跑」推到「能驗(yàn)收」的人不適合想找拖拽式設(shè)計(jì)器、指望完全不寫 XAML 的人。2. 拆目錄結(jié)構(gòu)主題 Token、控件模板、窗口外殼這三層怎么分拿到一個(gè)界面框架先別急著運(yùn)行 Demo也別急著往自己的工程里復(fù)制。先看Themes目錄的層次因?yàn)樗鼪Q定了后面所有覆蓋、換膚、定制動(dòng)作能不能生效。這套框架的劃分是比較典型的做法Tokens放純值顏色、字號(hào)、圓角、間距、控件高度Controls放控件樣式與ControlTemplateSkins放皮膚覆蓋Shell放窗口外殼與標(biāo)題欄。分層的意義在于職責(zé)邊界清晰Token 里不該出現(xiàn)任何ControlTemplate控件模板里不該出現(xiàn)任何寫死的#2F6FED。我見過太多項(xiàng)目的資源字典是一個(gè)幾千行的Styles.xaml顏色、模板、動(dòng)畫、轉(zhuǎn)換器全塞在一起。這種文件在項(xiàng)目第三個(gè)月就會(huì)變成黑匣子誰都不敢刪任何一行因?yàn)椴恢绖h了會(huì)影響哪個(gè)頁面。分層不是潔癖是為了讓你敢改。2.1 先看資源字典的合并順序它決定后面所有覆蓋能不能生效WPF 在MergedDictionaries里查找同一個(gè) Key 時(shí)后加入的字典優(yōu)先級(jí)更高。這條規(guī)則很短但它是整套換膚機(jī)制的基石。很多人的皮膚切換做不出來原因就一個(gè)把皮膚字典加在了 Token 字典前面于是 Token 里的舊值一直勝出換膚看起來「沒反應(yīng)」。正確的合并順序是先 Token再 Controls最后 Skin。!-- App.xamlxmlns 省略實(shí)際工程里按模板生成的寫 -- Application.Resources ResourceDictionary ResourceDictionary.MergedDictionaries !-- 第 1 層純值沒有任何模板。換膚就是換這一層的值 -- ResourceDictionary SourceThemes/Tokens/Colors.Default.xaml/ ResourceDictionary SourceThemes/Tokens/Typography.xaml/ ResourceDictionary SourceThemes/Tokens/Metrics.xaml/ !-- 第 2 層控件模板只允許引用第 1 層的 Key -- ResourceDictionary SourceThemes/Controls/Button.xaml/ ResourceDictionary SourceThemes/Controls/TextBox.xaml/ ResourceDictionary SourceThemes/Controls/Card.xaml/ !-- 第 3 層皮膚覆蓋第 1 層同名 Key必須放最后 -- ResourceDictionary SourceThemes/Skins/Light.xaml/ /ResourceDictionary.MergedDictionaries /ResourceDictionary /Application.Resources這段順序背后有兩條必須記住的規(guī)則。第一條是查找方向MergedDictionaries的檢索是從后往前所以最后加載的皮膚能蓋住前面所有同名 Key。第二條是作用域Application.Resources是全局的窗口和控件會(huì)逐級(jí)向上查找一旦某一層出現(xiàn)了同名 Key上層的就永遠(yuǎn)取不到——調(diào)試時(shí)「樣式在別的頁面正常、就這個(gè)頁面不對(duì)」八成是這個(gè)頁面的Window.Resources里藏了一個(gè)同名項(xiàng)??绯绦蚣脮r(shí)路徑要改成 pack URI比如pack://application:,,,/YourApp;component/Themes/Tokens/Colors.Default.xaml程序集名寫錯(cuò)的話運(yùn)行時(shí)會(huì)拋IOException而不是編譯錯(cuò)誤這也是常見的第一道問題。2.2 顏色、字號(hào)、圓角三組 Token為什么主色要用 DynamicResourceToken 層只做一件事把「設(shè)計(jì)決定」變成「命名常量」。這套框架里大致是三類鍵名前綴即語義分類示例 Key典型值說明顏色Color.Accent.Base#2F6FED主色另配 Hover、Pressed 兩檔顏色Color.Surface.Card#FFFFFF卡片、面板底色字號(hào)Font.Size.Body13正文另有 Caption 12、Title 18圓角Radius.Control6按鈕、輸入框統(tǒng)一圓角間距Space.Unit8所有間距取它的整數(shù)倍尺寸Metric.Control.Height32單行控件標(biāo)準(zhǔn)高度主色不要只給一個(gè)值Hover 和 Pressed 要手調(diào)出來別用Opacity疊。原因是透明疊加的結(jié)果依賴背景色同一個(gè)按鈕放在白色卡片和深色側(cè)欄上淺色疊加出來的效果完全不同深色背景上會(huì)發(fā)灰。這是很常見的視覺問題單看沒問題一放到深色區(qū)域就顯得臟。!-- Tokens/Colors.Default.xaml -- ResourceDictionary xmlns... xmlns:x... !-- 主色三檔Hover/Pressed 手工調(diào)深保證在深色和淺色背景上都成立 -- Color x:KeyColor.Accent.Base#2F6FED/Color Color x:KeyColor.Accent.Hover#245BD0/Color Color x:KeyColor.Accent.Pressed#1C48A8/Color !-- Brush 單獨(dú)一層控件模板里用 Brush換膚時(shí)只換 Brush 即可 -- SolidColorBrush x:KeyBrush.Accent.Base Color{StaticResource Color.Accent.Base}/ SolidColorBrush x:KeyBrush.Accent.Hover Color{StaticResource Color.Accent.Hover}/ SolidColorBrush x:KeyBrush.Text.OnAccent Color#FFFFFF/ SolidColorBrush x:KeyBrush.Surface.Card Color#FFFFFF/ !-- 字號(hào)與度量數(shù)值型 Token 用 sys:Double必須帶命名空間 -- sys:Double x:KeyFont.Size.Body13/sys:Double sys:Double x:KeyFont.Size.Title18/sys:Double CornerRadius x:KeyRadius.Control6/CornerRadius sys:Double x:KeyMetric.Control.Height32/sys:Double /ResourceDictionary關(guān)鍵在于「顏色」和「畫筆」分成兩層。Color是不可變結(jié)構(gòu)體SolidColorBrush才是控件屬性真正吃的東西模板里引用的必須是 Brush。數(shù)值型 Token 要注意類型x:Double需要引入sys命名空間clr-namespace:System;assemblySystem.Runtime不同目標(biāo)框架程序集名略有差異CornerRadius直接寫元素即可不用額外命名空間?,F(xiàn)在說DynamicResource和StaticResource怎么選這是最常被問的一個(gè)問題。結(jié)論是會(huì)隨皮膚變化的 Key 用DynamicResource永不變的 Key 用StaticResource。StaticResource在 XAML 解析時(shí)就把值取出來定死換膚后不會(huì)重新求值所以把主色用StaticResource引到模板里切皮膚必然失敗DynamicResource每次取值走一次資源查找會(huì)帶來額外開銷在DataGrid單元格模板、ItemsControl項(xiàng)模板這種會(huì)實(shí)例化成千上萬次的地方能靜態(tài)就靜態(tài)。我的習(xí)慣是Token 里跟顏色相關(guān)的全用DynamicResource字號(hào)、圓角、間距這類換膚不動(dòng)的用StaticResource。這個(gè)劃分一句話能記住后面維護(hù)的人也不會(huì)亂改。2.3 拆一個(gè)按鈕從 Token 到 ControlTemplate 的完整鏈路理解了層次再拆一個(gè)具體控件看看這套框架里一個(gè)主按鈕是怎么拼起來的。這段值得逐行讀因?yàn)樗呛竺嫠锌丶哪0濉?-- Controls/Button.xaml只引用 Token不出現(xiàn)任何字面色值 -- Style x:KeyButton.Primary TargetTypeButton Setter PropertyHeight Value{StaticResource Metric.Control.Height}/ Setter PropertyMinWidth Value72/ Setter PropertyPadding Value16,0/ Setter PropertyFontSize Value{StaticResource Font.Size.Body}/ Setter PropertyForeground Value{DynamicResource Brush.Text.OnAccent}/ Setter PropertyBackground Value{DynamicResource Brush.Accent.Base}/ Setter PropertyBorderThickness Value0/ Setter PropertyCursor ValueHand/ Setter PropertyTemplate Setter.Value ControlTemplate TargetTypeButton Border x:NameBd Background{TemplateBinding Background} CornerRadius{StaticResource Radius.Control} SnapsToDevicePixelsTrue ContentPresenter HorizontalAlignmentCenter VerticalAlignmentCenter Margin{TemplateBinding Padding} RecognizesAccessKeyTrue/ /Border ControlTemplate.Triggers !-- 順序有講究后定義的觸發(fā)器優(yōu)先級(jí)更高 -- Trigger PropertyIsMouseOver ValueTrue Setter TargetNameBd PropertyBackground Value{DynamicResource Brush.Accent.Hover}/ /Trigger Trigger PropertyIsPressed ValueTrue Setter TargetNameBd PropertyBackground Value{DynamicResource Brush.Accent.Pressed}/ /Trigger Trigger PropertyIsEnabled ValueFalse Setter TargetNameBd PropertyOpacity Value0.45/ Setter PropertyCursor ValueArrow/ /Trigger /ControlTemplate.Triggers /ControlTemplate /Setter.Value /Setter /Style這里有幾個(gè)容易被忽略的細(xì)節(jié)每一個(gè)都可能變成后期幾分鐘甚至幾小時(shí)地去排查的問題。第一TemplateBinding是單向的、不支持轉(zhuǎn)換器且只能綁到模板化父級(jí)的屬性上。所以Padding能綁Background能綁但如果你想把Background轉(zhuǎn)成漸變就必須換成{Binding Background, RelativeSource{RelativeSource TemplatedParent}}再掛 Converter?;煊眠@兩者時(shí)不要抱有僥幸心理模板里一旦出現(xiàn)轉(zhuǎn)換需求就整體換成Binding。第二觸發(fā)器順序決定最終效果。IsMouseOver和IsPressed同時(shí)為真時(shí)后定義的IsPressed生效所以按下色必須寫在懸停色后面。反過來寫按下時(shí)看到的還是懸停色看起來就像「按下沒反饋」。第三IsEnabledFalse時(shí)如果只改OpacityCursorHand依然生效鼠標(biāo)移上去還是手型用戶會(huì)以為可以點(diǎn)。所以禁用態(tài)要順手把Cursor也改回來這類細(xì)節(jié)在驗(yàn)收時(shí)最容易被挑出來。最后控件模板里不要出現(xiàn)字面色值這是硬性約束。只要模板里出現(xiàn)一個(gè)#2F6FED換膚那一刻它就會(huì)變成色塊不一致的元兇而且很難靠肉眼定位到具體是哪個(gè)模板??蚣芾镞@類違規(guī)用一次文本搜索就能找出來接入前先搜一遍#順手清理掉。3. 接入現(xiàn)有工程從復(fù)制目錄到跑出第一個(gè)頁面3.1 目錄落位與 csproj 里的資源聲明把整個(gè)工程復(fù)制進(jìn)來是最快的驗(yàn)證方式但真正接入現(xiàn)有項(xiàng)目時(shí)建議只復(fù)制Themes和Infrastructure兩個(gè)目錄示例頁按需挑選著拿。目錄放在項(xiàng)目根下即可不要塞進(jìn)Properties或者obj旁邊obj目錄在清理時(shí)容易誤刪。csproj這塊有個(gè)高頻問題SDK 風(fēng)格工程的默認(rèn) glob 已經(jīng)把**/*.xaml編譯成Page你再手寫一遍Page IncludeThemes\**\*.xaml /就會(huì)報(bào)重復(fù)項(xiàng)NETSDK1022。所以大部分情況下什么都不用寫只在需要排除或者改變構(gòu)建方式時(shí)才動(dòng)它。ItemGroup !-- 默認(rèn) glob 已包含 **/*.xaml這里只做排除草稿目錄不參與編譯 -- Page RemoveThemes\_draft\**\*.xaml / !-- 字體、圖標(biāo)這類二進(jìn)制資源用 Resource隨程序集嵌入pack URI 才取得到 -- Resource IncludeAssets\Fonts\*.ttf / Resource IncludeAssets\Icons\*.png / !-- 示例數(shù)據(jù)用 Content 復(fù)制到輸出目錄別用 Resource 塞進(jìn)程序集 -- Content IncludeSampleData\*.json CopyToOutputDirectoryPreserveNewest / /ItemGroup構(gòu)建項(xiàng)的選擇直接決定資源能不能取到這張表建議存下來構(gòu)建項(xiàng)編譯結(jié)果適用場景取用方式Page編譯為 BAML所有 XAML包括資源字典Source相對(duì)路徑Resource嵌入程序集字體、圖標(biāo)、小圖片pack://application:,,,/程序集;component/路徑Content原樣復(fù)制到輸出目錄示例數(shù)據(jù)、可替換配置相對(duì)輸出目錄的路徑None不處理文檔、說明無字體用Resource嵌入之后在 XAML 里通過FontFamily/Assets/Fonts/#字體內(nèi)部名引用注意斜杠后面那個(gè)#后面跟的是字體家族名不是文件名。寫錯(cuò)了不會(huì)報(bào)錯(cuò)只會(huì)靜默回退到系統(tǒng)默認(rèn)字體——這類靜默失敗最耗時(shí)間。3.2 App.xaml 合并字典與運(yùn)行時(shí)換膚皮膚切換不要用「先清空再添加」的寫法。清空MergedDictionaries會(huì)在瞬間讓所有DynamicResource失效控件重繪時(shí)可能拋出找不到資源的異常而「只添加不移除」會(huì)讓字典越積越多切換五十次之后內(nèi)存和查找開銷都會(huì)肉眼可見地上漲。正確做法是把皮膚字典固定在MergedDictionaries的最后一位換膚就是替換這一項(xiàng)。public static class ThemeManager { // 皮膚字典固定放在 MergedDictionaries 的末位替換這一項(xiàng)即為換膚 private static readonly Uri LightSkin new(pack://application:,,,/YourApp;component/Themes/Skins/Light.xaml); private static readonly Uri DarkSkin new(pack://application:,,,/YourApp;component/Themes/Skins/Dark.xaml); public static void Apply(bool dark) { var merged Application.Current.Resources.MergedDictionaries; if (merged.Count 0) return; var skin new ResourceDictionary { Source dark ? DarkSkin : LightSkin }; // 關(guān)鍵替換而不是 Add避免字典無限增長 merged[merged.Count - 1] skin; } }替換完成后不需要手動(dòng)刷新任何控件DynamicResource會(huì)自動(dòng)重新求值。這里有個(gè)前提所有隨皮膚變化的引用必須是DynamicResource只要模板里漏了一個(gè)StaticResource換膚后那個(gè)控件就會(huì)保持舊色在一片新配色里顯得很突兀。還要注意換膚的時(shí)機(jī)。啟動(dòng)時(shí)在App構(gòu)造函數(shù)里調(diào)用是最穩(wěn)的如果放在窗口Loaded之后用戶會(huì)看到一次明顯的閃爍。真想做到無閃爍就得在窗口顯示前把皮膚定好也就是把配置讀取提前到App初始化階段。3.3 無邊框窗口外殼與自定義標(biāo)題欄這套框架的外殼用的是WindowChrome而不是WindowStyleNone加AllowsTransparencyTrue。后者雖然也能做出無邊框效果但會(huì)讓窗口失去硬件加速路徑拖動(dòng)和縮放時(shí)明顯發(fā)澀圓角邊緣還會(huì)有鋸齒。WindowChrome保留系統(tǒng)窗口的非客戶區(qū)行為只把繪制權(quán)交給你。!-- Shell/AppWindow.xaml無邊框外殼保留系統(tǒng)縮放與拖拽行為 -- Window x:ClassYourApp.Shell.AppWindow WindowStyleNone ResizeModeCanResize AllowsTransparencyFalse Background{DynamicResource Brush.Surface.Card} !-- CaptionHeight頂部可拖拽區(qū)高度等于標(biāo)題欄高度 -- !-- ResizeBorderThickness邊緣拖拽熱區(qū)觸屏場景建議放大到 8 -- WindowChrome.WindowChrome WindowChrome CaptionHeight40 ResizeBorderThickness6 GlassFrameThickness0 CornerRadius0 UseAeroCaptionButtonsFalse/ /WindowChrome.WindowChrome Grid Grid.RowDefinitions RowDefinition Height40/ RowDefinition Height*/ /Grid.RowDefinitions !-- 標(biāo)題欄區(qū)域內(nèi)的按鈕必須聲明 IsHitTestVisibleInChrome否則點(diǎn)不到 -- StackPanel Grid.Row0 OrientationHorizontal HorizontalAlignmentRight WindowChrome.IsHitTestVisibleInChromeTrue Button Content— Style{StaticResource Button.Caption}/ Button Content□ Style{StaticResource Button.Caption}/ Button Content× Style{StaticResource Button.Caption}/ /StackPanel ContentPresenter Grid.Row1 Content{Binding Body}/ /Grid /Window三個(gè)參數(shù)決定了使用手感。CaptionHeight要和標(biāo)題欄那一行的高度嚴(yán)格對(duì)齊寫 40 就是 40寫小了頂部會(huì)剩一條既不能拖也不能點(diǎn)的死區(qū)ResizeBorderThickness在鼠標(biāo)場景 6 夠了觸屏設(shè)備建議 8 到 10否則邊緣拖不動(dòng)GlassFrameThickness0去掉系統(tǒng)玻璃層避免深色皮膚下邊緣發(fā)亮。標(biāo)題欄里的按鈕必須加WindowChrome.IsHitTestVisibleInChromeTrue這一條不加按鈕會(huì)變成「看得見點(diǎn)不著」鼠標(biāo)事件被拖拽區(qū)吃掉了。這是無邊框窗口最常見的一個(gè)問題排查時(shí)容易往命令綁定上想繞一圈才發(fā)現(xiàn)是命中測試。另一個(gè)是最大化蓋住任務(wù)欄。無邊框窗口最大化時(shí)系統(tǒng)給的尺寸包含非工作區(qū)直接鋪滿會(huì)頂?shù)羧蝿?wù)欄。簡單的做法是在窗口構(gòu)造里設(shè)MaxHeight SystemParameters.MaximizedPrimaryScreenHeight多顯示器場景下這個(gè)值只在主屏正確需要監(jiān)聽WM_GETMINMAXINFO自己算工作區(qū)框架的Shell目錄里有對(duì)應(yīng)的輔助類接入時(shí)按屏幕數(shù)量確認(rèn)一下。3.4 驗(yàn)收入口DPI、縮放、多屏的檢查清單界面框架接進(jìn)去功能點(diǎn)兩下都正常不代表能交付。下面這張表是我每次接入必過的一遍成本不到十分鐘能提前擋掉大部分返工。檢查項(xiàng)操作不通過的表現(xiàn)單屏 100%系統(tǒng)縮放調(diào)到 100%逐頁翻一遍1px 邊框消失或變粗單屏 150%縮放到 150%看文字與圖標(biāo)文字發(fā)虛、圖標(biāo)模糊多屏不同縮放兩屏分別設(shè) 100% 和 150%拖窗口來回拖到另一屏后整體變糊高對(duì)比度切換系統(tǒng)高對(duì)比度主題文字與背景同色看不見觸摸觸屏設(shè)備上點(diǎn)邊緣縮放邊緣拖不動(dòng)最小尺寸拖到最小寬高標(biāo)題欄按鈕被擠出可視區(qū)DPI 那一欄解釋一下WPF 是邏輯像素體系縮放變化時(shí)如果圖片資源只準(zhǔn)備了一份系統(tǒng)會(huì)拉伸結(jié)果就是模糊。圖標(biāo)盡量用矢量路徑位圖則按 100%、150%、200% 各備一份靠Image的尺寸選擇邏輯去匹配。這條不做用戶在 150% 縮放的筆記本上第一眼就會(huì)覺得「這軟件有點(diǎn)舊」。4. MVVM 骨架命令、通知、導(dǎo)航與對(duì)話框怎么切界面層的活干完接著看骨架。這套框架的Infrastructure目錄里放的是一套很薄的基礎(chǔ)設(shè)施ViewModelBase、RelayCommand、AsyncCommand、導(dǎo)航服務(wù)、對(duì)話框服務(wù)。判斷一套 MVVM 骨架好不好標(biāo)準(zhǔn)只有一條ViewModel 里能不能完全不出現(xiàn)Window、MessageBox、Application.Current。出現(xiàn)了單測就廢了復(fù)用也別想了。4.1 ViewModelBase屬性通知與 SetProperty 的寫法public abstract class ViewModelBase : INotifyPropertyChanged { public event PropertyChangedEventHandler? PropertyChanged; // 返回 bool方便 setter 里鏈?zhǔn)酵ㄖ缮鷮傩?protected bool SetPropertyT(ref T field, T value, [CallerMemberName] string? name null) { // 用 EqualityComparer 而不是 object.Equals避免值類型裝箱 if (EqualityComparerT.Default.Equals(field, value)) return false; field value; OnPropertyChanged(name); return true; } protected void OnPropertyChanged([CallerMemberName] string? name null) PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); }CallerMemberName省掉了手寫屬性名字符串改屬性名時(shí)不會(huì)漏改通知。相等判斷用EqualityComparerT.Default而不是因?yàn)榉盒屠飳?duì)值類型是裝箱比較屬性高頻更新時(shí)這點(diǎn)開銷會(huì)積少成多。返回bool是個(gè)很實(shí)用的小設(shè)計(jì)if (SetProperty(ref _name, value)) OnPropertyChanged(nameof(DisplayName));這樣派生屬性只在真正變化時(shí)通知避免無謂的綁定刷新。老項(xiàng)目里常見的寫法是 setter 里連續(xù)調(diào)三次OnPropertyChanged每次輸入都觸發(fā)一輪完整重算。集合屬性是另一個(gè)問題點(diǎn)。ObservableCollectionT不要每次賦值都new那等于讓ItemsControl重建整個(gè)視圖樹滾動(dòng)位置會(huì)跳回頂部。正確做法是初始化一次之后用Clear()加Add()更新。4.2 RelayCommand 與 AsyncCommandCanExecute 刷新時(shí)機(jī)的坑public sealed class RelayCommand : ICommand { private readonly Actionobject? _execute; private readonly Funcobject?, bool? _canExecute; public RelayCommand(Actionobject? execute, Funcobject?, bool? canExecute null) { _execute execute ?? throw new ArgumentNullException(nameof(execute)); _canExecute canExecute; } public bool CanExecute(object? parameter) _canExecute?.Invoke(parameter) ?? true; public void Execute(object? parameter) _execute(parameter); public event EventHandler? CanExecuteChanged { add CommandManager.RequerySuggested value; remove CommandManager.RequerySuggested - value; } // 手動(dòng)觸發(fā)異步命令結(jié)束、集合變化后必須調(diào) public void RaiseCanExecuteChanged() CommandManager.InvalidateRequerySuggested(); }CommandManager.RequerySuggested是隱式刷新只在鍵盤、鼠標(biāo)等輸入事件之后觸發(fā)。這意味著如果你在后臺(tái)線程里改了某個(gè)標(biāo)志位按鈕的可用狀態(tài)可能要等到用戶點(diǎn)一下別的地方才更新。血淚經(jīng)驗(yàn)是異步命令執(zhí)行完畢、批量數(shù)據(jù)加載完成這類時(shí)刻必須顯式調(diào)一次RaiseCanExecuteChanged()否則用戶會(huì)看到「按鈕還是灰的但功能其實(shí)已經(jīng)好了」。異步命令額外要處理兩件事。一是防重入執(zhí)行中把CanExecute置為false避免用戶連點(diǎn)三次發(fā)出三個(gè)請(qǐng)求。二是異常兜底async void里拋出的異常會(huì)直接打到未處理異常上進(jìn)程就掛了??蚣芾锏腁syncCommand用try/catch包住執(zhí)行體把異常交給注入的錯(cuò)誤處理器再由它彈提示。public sealed class AsyncCommand : ICommand { private readonly Funcobject?, Task _execute; private readonly Funcobject?, bool? _canExecute; private bool _isRunning; // 防重入標(biāo)志 public AsyncCommand(Funcobject?, Task execute, Funcobject?, bool? canExecute null) { _execute execute; _canExecute canExecute; } public bool CanExecute(object? parameter) !_isRunning (_canExecute?.Invoke(parameter) ?? true); public async void Execute(object? parameter) { if (_isRunning) return; _isRunning true; RaiseCanExecuteChanged(); try { await _execute(parameter); } catch (Exception ex) { // 必須兜住async void 里的異常無處可去 ErrorHandler?.Invoke(ex); } finally { _isRunning false; RaiseCanExecuteChanged(); } } public event ActionException? ErrorHandler; public event EventHandler? CanExecuteChanged; public void RaiseCanExecuteChanged() CanExecuteChanged?.Invoke(this, EventArgs.Empty); }AsyncCommand我沒有復(fù)用CommandManager而是自己維護(hù)CanExecuteChanged。原因是異步場景下按鈕狀態(tài)變化跟輸入事件沒有必然關(guān)系走隱式刷新容易失準(zhǔn)自己控制雖然要多調(diào)幾次RaiseCanExecuteChanged但行為可預(yù)期。4.3 導(dǎo)航與對(duì)話框接口怎么切才不綁死 UI接口切分的目標(biāo)是讓 ViewModel 只描述「要什么」不描述「怎么顯示」。這張表是框架里的切法接口職責(zé)不該做的事INavigationService按 ViewModel 類型切換主區(qū)域內(nèi)容不引用具體Page、Window類型IDialogService確認(rèn)框、輸入框、等待提示不直接調(diào)MessageBoxINotificationService頂欄消息、Toast不持有具體控件的引用IThemeService讀取與切換皮膚不碰Application.Resources的索引public interface IDialogService { // 返回 Task調(diào)用方 await 之后拿結(jié)果避免回調(diào)地獄 Taskbool ConfirmAsync(string title, string message); Taskstring? PromptAsync(string title, string message, string? defaultValue null); }實(shí)現(xiàn)側(cè)常見的做法是用一個(gè)覆蓋全窗口的ContentControl加半透明遮罩把對(duì)話框內(nèi)容當(dāng)作普通控件渲染返回值靠TaskCompletionSourcebool在用戶點(diǎn)擊時(shí)SetResult。這樣對(duì)話框也吃同一套 Token深色皮膚下不會(huì)出現(xiàn)一個(gè)白底黑字的系統(tǒng)彈窗視覺上跳出來。這里要提醒一點(diǎn)TaskCompletionSource必須用TaskCreationOptions.RunContinuationsAsynchronously否則SetResult會(huì)在 UI 線程上同步跑完整個(gè)await后續(xù)邏輯遇到重活就卡界面。這個(gè)問題非常隱蔽表現(xiàn)為「點(diǎn)確認(rèn)之后界面頓一下」把選項(xiàng)加上就好。5. 避坑記錄樣式不生效、內(nèi)存上漲、DPI 模糊的排查順序這一章是這份框架里最值得先讀的部分。下面四條都是我在真實(shí)接入里遇到過的每一條按現(xiàn)象、原因、解決的順序?qū)懹龅酵悊栴}時(shí)可以照著順序查。5.1 現(xiàn)象改了 Token控件紋絲不動(dòng)現(xiàn)象把Color.Accent.Base從藍(lán)改成橙重新生成主按鈕還是藍(lán)的。清緩存、重啟 IDE 都試過仍然是藍(lán)。原因控件模板里引用的是{StaticResource Brush.Accent.Base}。StaticResource在 BAML 解析階段就把值取出來寫死了后續(xù)字典變化對(duì)它沒有任何影響。另一種可能是這個(gè)頁面的Window.Resources里定義了一個(gè)同名的Brush.Accent.Base局部作用域優(yōu)先全局的改動(dòng)被它遮住。解決在解決方案里搜StaticResource Brush.凡是顏色類的引用全部換成DynamicResource再逐頁檢查Window.Resources和UserControl.Resources里有沒有同名 Key。這兩步做完改動(dòng)立即生效。我的習(xí)慣是把這條寫進(jìn)代碼評(píng)審清單模板里出現(xiàn)StaticResource后面跟Brush.前綴的一律打回。5.2 現(xiàn)象切幾次皮膚內(nèi)存一路往上走現(xiàn)象在設(shè)置頁反復(fù)切換淺色和深色任務(wù)管理器里的內(nèi)存從 180MB 漲到 400MB 不回落切得越多漲得越多。原因換膚實(shí)現(xiàn)寫成了merged.Add(skin)每次切換都往MergedDictionaries里追加一個(gè)字典舊字典既沒被移除也沒被回收資源查找還得從后往前遍歷一長串。另一個(gè)隱性原因是畫筆沒凍結(jié)SolidColorBrush每次創(chuàng)建都是新的可凍結(jié)對(duì)象沒調(diào)Freeze()就參與變更通知無法被共享。解決換膚改成替換末位元素見 3.2 的寫法Token 里所有SolidColorBrush在創(chuàng)建后調(diào)一次Freeze()凍結(jié)后的畫筆可以被多個(gè)控件共享內(nèi)存占用會(huì)明顯下降。改完再測反復(fù)切換五十次內(nèi)存曲線基本走平。提示Freeze()只能用于可凍結(jié)對(duì)象而且凍結(jié)后不能再改屬性。如果某個(gè)畫筆需要在運(yùn)行時(shí)調(diào)色就別凍結(jié)它。5.3 現(xiàn)象4K 屏上字體發(fā)虛、1px 邊框消失現(xiàn)象開發(fā)機(jī) 100% 縮放一切正常換到 150% 縮放的筆記本上正文明顯發(fā)糊卡片之間的 1px 分隔線時(shí)有時(shí)無圓角處還有毛邊。原因三個(gè)疊加問題。位圖圖標(biāo)只準(zhǔn)備了一份系統(tǒng)拉伸導(dǎo)致模糊Border的BorderThickness用了1但沒開UseLayoutRounding和SnapsToDevicePixels在非整數(shù)縮放比下 1px 被攤到兩個(gè)物理像素上顏色被稀釋到看不見再就是窗口設(shè)了AllowsTransparencyTrue透明窗口在部分縮放下失去硬件渲染路徑。解決圖標(biāo)改用矢量路徑在外殼根元素上開UseLayoutRoundingTrue需要像素對(duì)齊的Border和Image加SnapsToDevicePixelsTrue無邊框窗口換回WindowChrome方案。三條一起改150% 下再對(duì)比截圖邊緣和文字都恢復(fù)銳利。5.4 現(xiàn)象設(shè)計(jì)器里正常運(yùn)行時(shí)拋 XamlParseException現(xiàn)象XAML 在設(shè)計(jì)器里預(yù)覽得好好的一運(yùn)行就拋XamlParseException提示找不到某個(gè)資源堆棧指向一個(gè)看起來沒問題的Setter。原因StaticResource的解析是編譯期決定的它只能向前查找——引用必須出現(xiàn)在定義之后或者定義在更早就合并的字典里。設(shè)計(jì)器有時(shí)會(huì)更寬松地加載于是出現(xiàn)「設(shè)計(jì)器能看、跑起來就崩」。另一種原因是跨程序集引用時(shí) pack URI 里的程序集名寫錯(cuò)編譯期不校驗(yàn)運(yùn)行時(shí)才爆。解決先在App.xaml里把 Token 字典排在最前面確保所有模板在后面再檢查所有跨程序集的Source程序集名、大小寫、component關(guān)鍵字都要對(duì)上。定位技巧是把App.xaml里的合并字典臨時(shí)注釋掉一半二分法很快能鎖定是哪個(gè)文件。5.5 常見問題速查表癥狀第一嫌疑快速驗(yàn)證換膚后個(gè)別控件不變色模板里用了StaticResource全工程搜StaticResource Brush.按鈕點(diǎn)不動(dòng)標(biāo)題欄命中測試被吃檢查IsHitTestVisibleInChrome最大化蓋住任務(wù)欄無邊框窗口的尺寸計(jì)算看MaxHeight是否按工作區(qū)算列表刷新后滾動(dòng)條跳頂集合被整體new檢查ObservableCollection賦值處命令按鈕一直灰隱式刷新未觸發(fā)手動(dòng)調(diào)一次RaiseCanExecuteChanged字體不是預(yù)期那個(gè)FontFamily的家族名寫錯(cuò)核對(duì)#后面是家族名而非文件名6. 進(jìn)階把換膚做成可以回歸驗(yàn)證的流程界面類的改動(dòng)最難驗(yàn)證因?yàn)樗缚雌饋頉]問題」和「確實(shí)沒問題」之間差得很遠(yuǎn)。這套框架里我最常用的一個(gè)技巧是把換膚做成可以對(duì)比的回歸流程。第一步把 Token 抽出來做一份中間格式??蚣艿腡okens目錄本身就是鍵值對(duì)用幾十行代碼掃一遍 XAML把Color.*、Font.Size.*、Radius.*導(dǎo)出成 JSON交給設(shè)計(jì)側(cè)對(duì)齊。之后設(shè)計(jì)師改配色改的是這份 JSON工程師用腳本回寫 XAML比在群里發(fā)色值截圖靠譜得多?;貙懩_本要注意保留原有的x:Key順序和縮進(jìn)否則每次生成都是幾百行 diff評(píng)審時(shí)沒人看得下去。第二步準(zhǔn)備一個(gè)「Token 全覽頁」。把所有 Token 渲染成色塊、字號(hào)樣例、圓角樣例配上鍵名放在調(diào)試菜單里。換膚以后直接翻這一頁哪個(gè)鍵沒被覆蓋一眼就能看出來。這個(gè)頁面我一般不到半小時(shí)就能拼完但省下來的排查時(shí)間遠(yuǎn)超投入。第三步截圖比對(duì)。把關(guān)鍵頁面在淺色和深色下各截一張存在版本庫里改了樣式之后重新截用逐像素差值定位變化區(qū)域。閾值不要設(shè)在零字體渲染有亞像素抖動(dòng)允許千分之三以內(nèi)的差異超過就是真改了。這套流程跑順之后改一個(gè) Token 影響哪些頁面提交前就能知道。還有一個(gè)小習(xí)慣值得說一下每次接入新的界面框架我都會(huì)先在空工程里跑一遍它的 Demo把所有頁面點(diǎn)一遍重點(diǎn)看深色皮膚下的對(duì)比度和禁用態(tài)。原因很簡單這些地方最容易藏問題而在自身工程里樣式問題會(huì)被業(yè)務(wù)邏輯掩蓋很難判斷到底是框架的問題還是你寫錯(cuò)了。從那以后我每次往項(xiàng)目里引 UI 框架都強(qiáng)制先走一遍這套空工程驗(yàn)證再動(dòng)業(yè)務(wù)代碼。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取
返回列表
PREV
查看更多資訊
NEXT
返回資訊列表
日韩av网站在线观看| 日本在线视频播放91| AV性爱在线| www、丁香五月天| 超碰在线成人| 射久久丁香五月| 九九热这里都是精品6| 丁香99| 五月丁香婷婷基地| 色婷婷电影网| 五月婷婷开心丁香| 99久久综合网| 婷婷丁香五月精品| 99热香港| 婷婷五月丁香狠狠| 色色色色色色色综合| 97色色网| 五月天亚洲综合网| 五月婷婷六月少妇激情| 思思久热| 99视频这里有精品免费观看| 色婷五月| 蜜桃婷婷丁香| 国精产品久久| 人人人操97| 这里只有精品视频222| 九色在线五月婷婷网址| www免费在线视频| 日本三级中国三级99人妇网站| 婷婷亚洲色| 秋霞三级影视资源| 激情丰满熟妇五月| 色综合网综合| 人人视频色| 成人必爱视| 成人 在线 日韩| 丁香色五月AV在线| 婷婷操超碰| 婷婷五月丁香成人网| 婷婷五月天网| 天天揷综合网| 丁香婷婷成年| 婷婷五月天丁香久久| 国产69久久久欧美黑人A片| www.99热视频| 中文字幕按摩做爰| 97爱艹婷婷开心丁香激情综合| 亚洲色啪| 五月天啪啪| 天天婷婷综合亚洲亚洲| 激情色色| www.第四色99| 69人妻人人澡人人爽久久| aaa久久久| 性av| 婷婷五月中文字幕| 婷婷射丁香| 日韩在线观看亚洲| 五月综合亚洲色| 日韩黄黄| 色婷婷六月开心中文字| 俺去也五月| xx人人xx| 婷婷91| 欧美精品18| 99热激情| 六月婷婷色色网| 99精品视频播放| 亚洲中文AV| 吾爱AV导航| 99免费偷拍视频| 超碰日日操| 色综合网址| 超碰AV在线| 99色婷婷| 婷婷五月丁香基地| 狠狠色狠狠操| 人人肏逼视频在线一区二区| 大香蕉久久久| 色婷婷a三区麻| 久久精品66| 亚洲情a| 激情综合五月开心狠狠| 六月激情网| 99欧美精品99日本精品| 97碰在线| 99热精品在线播放| 久热超碰| 色综合久久44| 五月激情久久综合网| 九九热在线99| 五月天婷婷影院| 亚洲成AV人片在线观看| 66精品国产成人| 青青草婷婷综合五月| 日韩色色视频www| 日本五月天网站| 九九视频在线| 综合激情在线观看| 伊人婷婷色激情丁香| 婷婷五月视屏| AA片在线观看视频在线播放| 182TV亚洲| 色婷婷久久综合久色| 99热这里只有精品 搜| 亚洲五月婷婷| 玖玖伊人网| AV伊人青草丁香六月| 婷婷五月六月激情| 中文字幕成人| 91九色在线| 牛牛碰免费| 久热九九| 五月天婷婷操逼视频| 天天操夜夜夜拍拍拍| 久久精品夜色噜噜亚洲a∨| 99精品在线| 日韩色色一区| 婷婷五月色天| 九九Y精品热播| aaaaa黄色| 国产无套精品一区二区| 夂夂夂夂夂夂夂夂夂夂夂夂夂夂夂夂夂夂夂亚洲亚洲亚洲亚洲亚洲亚洲亚洲亚洲色 | 日韩操女| 99免费热视频在线| 色九月综合| 少妇激情五月婷婷| 99久热| 婷婷五月精品中文字幕| 婷婷久久五月天| 99超碰欧美| 亚洲综合视频天天精品| 色播播五月天| 亚洲视频在线观看99| 婷婷中文字幕| 超碰免费大香蕉| 日韩色五月| 国产精产国品一二三在观看| 99热在线99| 色色操| 99免费偷拍视频| 五月宗合激情网| 免费观看全黄做爰的视频| 性爱先锋AV| 久热一本| 激情婷婷五月久久| 久久激情视频| 思思热在线精品视频网站| 99久久久99久久91熟女| 99小精品| 夜夜嗨一区二区三区直播内容 | 色蜜婷婷| 欧美一级色| 日本一级特黄大片AAAAA级| 亚洲aV写真天天综合网久久| 啪啪五月综合| 五月丁香六月婷| 免费观看亚洲AV片| 久操操| 丁香六月 婷婷六月| 婷婷综合五月天| 色情婷婷| AV成人在线网站| 精品婷婷五月视| 中文字幕日产A片在线看| 九九熱最新視頻| 久久婷婷五月| 狠狠操狠狠狠| 久婷久婷激情肉| 天天搡日日搡aaaaⅩ| 亚洲色人妻| 国产精品国产| 一根材五月婷成人| 亚洲精品成人片在线播| 色五月播五月| 丁香五月无码| 婷婷视频网| 欧洲色| 久草久青福利| 婷婷五月综合色中文字幕| 国产激情综合五月久久| 色五月天天在线观看资源站| 丁香五月婷婷香| 夜夜操激情| 五月婷婷激情日本| 国产精品国产成人国产三级| 婷婷五月天在线观看免费| 婷婷五月中文字幕| 91丁香综合| 99热这里只有精品在线播放 | 五月天婷婷黄色| 碰人人97| 五月天婷婷基地| 丁香婷婷久久老熟女综合网| 欧美日本黄色| av首页在线| www.色9| 天天搞夜夜叫| 五月婷婷六月综合| 丁香婷婷欧美综合| 九九激情网| 久色网五月| 96精品久久久久久久久| 日本波多野结衣视频| 亚洲天堂aaaa| 丁香婷婷伊人| 日本va欧美va精品发布视频| 伊人玖玖精品| 激情久久婷婷| 五月丁香综合色婷婷| 亚洲性视频| 777久久精品| 丁香五月天亚洲综合| 大香蕉婷婷久久| 九九一综合精品| 丁香五月综合激情性爱| 成人性生活免费观看。| 午夜不卡久久精品无码免费| 亚洲精品国产setv| 国产婷婷五月色情综合| 人人做人人看人人摸| 丁香婷婷六月天| 国内自拍97在线| 丁香五月天色婷婷| 狼友视频在线观看18| 99热这里精| 丁香九月婷婷综合| 五月婷婷色播| av成人在线播放| 狠狠精品干练久久久无码中文字幕| AV成人在线播放| 激情综合五月色丁香婷婷| 色色色99| 色五月综合在线| 久热伊人在91| 久操人| 玖玖99婷婷| 夜夜操夜夜操| 这里只有精品免费| 老司机日日夜夜青草| 99色性爰网络| 天天插天天射| 天堂在线9| 热久久99热欧美国产亚洲| 狠狠色丁香婷婷基地| 激情综合亚洲| 激情五月深爱五月| 伦乱美欧| 亚洲XX日本| 六月丁香婷婷综合色播| 九九人妻福利| 激情欧美婷五月| 五月丁香六月激情综合网| 色婷婷免费视频| 97人妻碰碰碰久久| 婷婷综合视频| 亚洲色色色色色色色色色| 99热欧美偷拍| 99ri视频| 千人斩操逼| 全网最新网黄大秀直播高清,主播国产录屏在线 | 六月狠狠综合| 99re热视频这里只精品5| 亭亭五月激情亚洲在线| 狠狠狠夜夜夜| 99碰网站| 婷婷五月天综合网| 99干日日干| 亚洲亚洲人成综合网络| 色五月婷婷久久| 五月之婷婷| 99色视频在线| 26uuu91| 久久久久久草黄色片AV在线观看| 五月天亚洲图片婷婷| 美腿丝袜AV天堂网| www.精品久9| 久久R激情| 欧美色婷婷| 婷婷色在线| 大香蕉久久婷婷精品综合| 国精产品一区二区三区| www.sezonghe| 成人超碰Av| 五月天色婷婷图片| 婷婷五月天视频在线观看| 另类色视频| 97香蕉碰碰人妻国产欧美| 亚洲免费视频网站| 久久久五月婷婷| 操比激情五月| 伊人玖玖婷婷| www.91操| 色五月婷婷激情综合网| 婷婷六月丁香激情综合| 五月丁香在线婷婷蜜桃| 99热这里只有精品无码| 色XX综合网| www.五月天激情| 日日爽日日爽| 色欲午夜无码久久久久久张津瑜 | 伊人玖玖精品| 婷婷香香五月| 西瓜美女a片| A A色色| 天天成人综合视频| 在线综合网| 亭亭玉月丁香| 热久精品| 韩国中文字幕91| 九一娱乐在线观看视频| 99精品超在线播放| 永久思思热在线| 99热在线里有精品| 五月天深爱激情网| 欧美 日韩 成人在线| 91久久综合亚洲鲁鲁五月天| 激情五月天色色| 中字幕视频在线永久在线观看免费| 九九热青草| 久久婷婷青青| 婷婷操久久| 狠狠干五月天婷婷网| 丁香五月天人体| 99思思热只有在这里看| 九月婷婷色色| 人妻丰满精品一区二区A片| 日韩专区五月天婷婷丁香| 在线成人国产| 青青草原中文字幕| 婷婷综合精品视频97| 99色五月| 色综合视频在线| 伊人久热91| 五月丁香啪啪网| 激情五月综合色婷婷| 五月天婷网| 熟女网站久久| 97色精品视频| 日本69日人视频| 欧美激情五月天在线观看| 深爱五月网| 激情久久久久久| 色婷婷成人做爰A片免费看网站| 青吴乐视频| 婷婷五月中文字幕| 六月激情婷婷色| 精品成人无码A片观看香草视频| 色色国产| 国产精品视频久久99| 亚洲va在线∨a天堂va欧美va| 伊人玖玖精品| 超碰在线免费观看3 9| 狠狠色丁香久久婷婷综合五月| 色五月综合在线| 激情五月天综合图片小说网站| 久久人妻www| 色五月五月婷婷| 五月婷婷av在线| 婷婷99狠狠躁天天躁中文| 9.1综合网| 色V狠狠的干| 丁香五月婷婷亚洲综合精品在线| 久久色亭亭五月天| 免费超碰在线观看| 久热视频A.| 99在线精品免费视频| 热九九精品| 99热香港| 九九99精品视频在线观看| 丁香六月激情综合啪啪| 99免费在线视频| 五月丁香趴趴| 色婷婷五月网| 激情五月天小说|五月天开心激情网|亚洲精品国产自在现线|黄色五月天 | 激情综合国产| 玖玖热视频| 五月天婷婷久久| 亚洲无码九九九| 人人干人人干骚美女| 26uuu欧美| 少妇AB又爽又紧无码网站| 一区二区三区XXXXXX| 日本va网站| 久久婷婷伊人| 日本欧美国产| 51国精产品自偷自偷综合| 色香欲综合| 丰满少妇猛烈A片免费看观看| 久久婷婷色综合| 五月丁香激情六月| 99无码视频| 色播播婷婷| 免费观看欧美成人AA片爱我多深 | 色五月综合| 爽极品色| 婷婷四色五月| 久久色五月天| 99热都是精品| 婷婷WWW久久| 99精品无码网站| 天天操夜夜操| 九九色中文| 另类 在线| 天天综合网色欲香| 国产精品热搜丁香五月婷婷| 色色色色丁香| 五月婷婷激清网| 五月婷婷六月色| 久久色婷婷| 久久小视频| 亚洲无码AV片| 青青草护士中出内射-欧美电影在线天堂新版 | 婷婷五月综合社区在线| 婷婷深爱五月丁香网| 日本精品人妻无码77777| 九九热a| 色色婷| 91精品国产99久久久久久天美| 色综合九九| 五月婷婷色白丝| 99热久草| 丁香五月婷婷综合激情啪啪啪啪啪啪啪| 五月婷婷六月激情网| 亚洲人人操| 一个色的综合| 天天色中文字幕女优AV| 五月开心深深爱激情综合| 色五月色开心开心五月| 色婷婷成人| 99se丁香| 五月开心久久| 爱射综合| 专区无日本视频高清8| 99热99ai| 777米奇影视第四色| 九九这里精品| 丁香五月婷婷少妇| 综合色影院| 五月婷婷色播| 熟女人妻一区二区三区免费看| 少妇丁香婷婷| 六月婷婷色色网| 国产一区男女| www.com.色色| www,天天干| 色五月综合婷婷久久综合婷婷久久综合婷婷久久综合婷婷久久 | 激情亚洲婷婷| 五月天社区| 婷婷五月天日日日干干干| 黃色三级三级三级三级 qixing300.shrkbk.com www.jinbozs.com tianmiaosw.com | 天天舔天天爽| 天天插天天草人人玩| W色综合| 日日舔夜夜操| 生活片五区| 婷婷久久丁香五月| 激情五月婷婷综合视频| 99免费青青蜜臀| 丁香九九九九| 激情丁香五月激情婷婷| 大香蕉人人网| 成人在线视频网| 五月天婷婷色小说| 欧美人人操| 国产精品18久久久| 久久金品黃色| 五月丁香六月综合情在线观看| 激情图片亚洲| 欧美色色色色色| 99热久只有精品首页| 大香蕉丁香五月| 九九色99| 99综合激情久久精品久久| 日韩av网站在线观看| 91欧美| 亚洲色情网站| 色五月综合婷婷久久综合婷婷久久综合婷婷久久综合婷婷久久 | 亚洲激情网站| 99热欧美| 久久久人人操A V| www久久99| 五月天婷婷丁香社区| www,色婷婷| 久久精品99国产精品日本| 另类激情五月在线视频欧美| 六月五月久久丁香| 婷婷月综合| 久久五月婷综合| 色五月成人| 丁香婷婷十月| 亚洲中文丁香| 国产在线黄色| 色综合av超碰| 99色爱| 99热激情| 激情网五月婷婷| 九九AV| 大香蕉太香蕉视频97| 五月丁香啪啪| 9久视频| 亚洲成人黄色网| 婷婷五月激情四月综合| 精品久久9| 热久免费视频9| 九九视频在线| 久久大香蕉同僚| 99免费视频网| 丁香五月婷婷88在线| 99无码视频| 99热99| 国产成人AV| 五月激情综合网| 亚洲成人中心| www,天天干| 天天插天天草人人玩| 婷婷九月| 嫩草视频在线观看| 色婷婷AV在线| 玖色色综合| Y11111111111少妇电影院| 99热官网| 99亚洲精品| 26uuu最新地址| 91凹凸在线| 99热99热在线| 逼里香不卡| 99爱无码| 亚洲色模骚货| 久99热| 亚洲人妻五月丁香婷婷| 99久久99热这里只有精品| 五五月丁香花激情综合网| 99久久久99久久91熟女| 在线成人网站| 丁香五月自拍| 久久五月综合| 99亚洲综合| 亚洲视频a| 超碰超碰在线| 99噜噜噜在线播放| 玖月婷婷爱丁香| 五月丁香婷婷网网网网| 六月色日韩| 99 热国产在| 91超级碰| 久久这里只有国产| 婷婷五月天,影院| 九九九九九无码| 五月天激情综合网站| 怡红院99| 思思99热这里只有精品6| 先锋资源996| 国产裸舞福利资源在线视频| 欧美色欲色欲天天天www| 丁香五月冃欧美| 天天夜夜六月丁香五月婷婷老师| 思思热精品在线视频| 亚洲免费婷婷| 国产熟女一区二区三区五月婷| 超碰人人超碰| 另类图片五月天| 五月丁香啪| 99热久久这里只有精品| 99久久婷婷综合| 色色五月综合| 内射综合网| 激情四射五月天偷偷看婷婷| 狠狠五月丁香色婷| 五月综合精品| 成人一级片| 婷婷五月天综合在线| 亚洲操逼网| 大陆极品少妇内射AAAAAA| 爱iii做iiii日日| 高清国产一级婬片a免费| 9久热免费视频99| 五月天开心激情网色欲无码| 久久婷婷五月综合色播| 久久99网| 色婷婷成人做爰A片免费看网站| 色色网站毛片| 久久婷婷综合拍| 99啪| 狠狠五月天激情| 丁香五月社区| 99免费视频| 琪琪色网址| 色婷婷丁香九月| 嫩草AV久久伊人妇女超级A| 丁香婷在线| 久久五月天色婷婷| 色色热| 性爱网六月丁香| 啪啪91| 丁香五月六月激情| 五月婷婷偷拍| 丁香六月丁香婷婷激情| 日本婷婷在线| www.五月天婷婷姐姐| 123草逼网| 丁香五月影院| 色婷婷91| 色丁香婷婷美女视频网站| 五月天婷婷综合网| 色欧美一级| 另类伊人婷婷| 色射婷婷五月天| 日本熟妇精品99| 国模狼狼| 六月婷婷之青青草| 五月婷婷综合视频| 久久AAAA片一区二区| 1024操逼视频| 丁香五月五婷| 丁香色色网| 日韩综合久| 超碰AAAAAAV| 婷婷人人操| av操B网站| 激情久久久| 色五月天在线观看| 久久看九九90| 五月婷婷与六月丁香图片激情| 大香蕉五月天婷婷丁香91| 色五月婷婷激情五月| 亚洲av成人在线| 丁香五月婷婷香| 色婷婷最爱五月| 亚洲中文字幕AV| 丁香五月天激情四射网络不好 | 中文AV网站| 第九色区av天堂| 亚洲AV无码影院| 婷婷综合五月天亚洲综合| 久热婷婷| 天天爽人人综合免费7799| 涩五月婷婷| 久操香蕉| 婷婷丁香五月精品| 99色综合| 精品五月视频婷婷在线观看| 色99在线观看| 思思99久久| 五月婷婷真爱激情网| 俺也去五月婷婷丁| 色色日韩无码| 欧美三级A做爰在线观看| WWW久久久| 123草逼网| 精品导航在线x不卡| 婷婷中文字幕版| 国精产品一区一区三区免费视频| 天天日天天做天天舔| 婷婷五月丁香啪啪| 黄色三级日本| 操97| 97久久精品| 色欲天天综合| 丁香五月91| 97热精品| 九九黄色网| 五月天色色色| 五月天婷婷激情网| 婷婷在线视频| 激情开心五月婷婷| 丁香五月天视频| 女人天堂av| 免费看欧美成人A片无码| 久久综合五月天| 九九色综合九九色| 久久精品色| 九九热视频精品| 丁香五月 综合| 精品久久99| 激情五月丁香色婷婷| 中文字幕无线久必| 亚洲久久婷婷| 超碰啪啪网| 五月婷婷丁香六月| 久久婷婷网| 天天夜夜六月丁香五月婷婷老师| 韩国不卡AC视频| 婷婷五月丁香伊人| 婷婷丁香九月| 天天干天干| 久久五月六月| 国产精女同一区二区三区久| 五月天另类小说| 丁香五月大香蕉AV| 天天日天天摸| 99久久成人| 七七色综合| 狼人婷婷久久| 开心五月天私房婷婷| 亚洲精品国产熟女久久久| 99日这里只有精品| 国产精品美女久久久久AV超清| 玖玖视频福利| 香蕉曰比| 五月丁香啪综合| 99re热| 99日热在线视频| 五月天成人综合| 99热这里只有精品268| 亚洲欧美在线观看| 五月色影院| 五月天激情国产综合婷婷婷就去爱| 操一区| 五月丁香花开综合网| 91干在线| 最近免费中文字幕大全高清大全1 免费看欧美成人A片无码 | 免费观看的av| 五月天久久网站| 久久色天堂| 六月丁花香啪啪激情欧美| 婷婷丁香五月网| 日木狠狠干| 丁香五月很很肏| 色色五月天婷婷| 久久五月丁香六月婷| 色婷婷激情五月天| 成人国产欧美大片一区| 99超级碰碰| 丁香久色| 丁香五月天.com| 草草女人亚洲| 欧美熟女99| 丁香婷婷五月六月天| 色五月综合在线| 久月久在线视频| 色色色色色色色色网站| 丁香五月激情鲁| 九九久久综合| 99五月婷| se色婷婷视频| 婷婷五月天小说网| 久久hd| 人人干人人操人人摸人人做| 7777激情基地| 99玖玖视频| 狠狠色丁香| 国产熟女一区二区三区五月婷| 天天摸天天高潮天天爽| 天天日天天添| 激情99| 五月六月婷| 久香草视频在线观看| 99色婷婷视频| 五月天婷婷激情在线色图| 大香蕉 婷婷| 五月丁香五月综合欧美| 婷婷五月香蕉| 婷婷亚洲五月| 九九热这里只有国产精品| 激情五月天在线观看色婷婷| 日本在线99| 97色精品视频 | 伊人色综合影院视频| 丁香五月婷婷激情中文| 97精品人人A片免费看| 九九九九毛片| 91九色中文字幕女在线观看| 99热亚洲精品| 日韩操逼小电影| 久久伊人婷| 女人被躁到高潮嗷嗷叫小| 97五月天| 久99视频| 丁香五月六月婷婷综合| 中文字幕色色| 99精品爱| 六月丁香激情综合| 丁香五月成人论坛| 天天五月丁香五月| 性爱网久久| www九九热| 成人视频一区| 97精品自拍| 婷婷五月激情综合啪啪| 激情综合婷婷久久| 五月丁香婷婷综合| 久久婷婷色| 婷婷久久五月丁香| 久大香蕉| 日本久久精品| 五月婷婷丁香| 97色婷婷| 婷婷午夜天| 丁香婷婷深情五月亚洲| 激情五月天色播| 很很干天天干| 中文字幕无码人妻少妇免费视频| 婷婷导航| 日韩丰满少妇无码内射| 99婷五月| 日本A片一区| 日韩三及成人AV片| 操逼巨乳91| 丁香五月天天久久综合小说| 这里有精品| 婷婷社区五月天| 少妇综合网| 日韩精品AV一区二区三区| 国产真人做爰视频免费| 97久久婷婷色| 9999综合99综合人| 色五月天丁香婷婷| 国产黄大片在线观看画质优化 | 欧美在线视频9| 婷婷丁香五月网| 玖玖伦理电影| 五月丁香六月日逼| 欧美激情xxxXX| 国产乱码久久| 97色五月天| 五月丁香婷婷俺| 婷婷激情综合| 99在线精品视频| 亚洲激情av| 影音先锋91在线资源站| 91刘玥视频在线观看| 婷婷久久精品| 噜噜色天天开心| 另类小说婷婷色| 丁香五月婷婷在线观看| 五月久久婷婷丁香| 久久久激情| 大香蕉手机视频| 丰满少妇乱A片无码| 91在线资源| 婷婷的99视频网站| 狠狠va| 老司机日日夜夜青草| www.色九月| 久久激情网| 色亭亭丁香五月天| 五月停停色色丁香| 丁香5月啪啪| 色婷婷五月天久久| 国产激情综合五月久久| 久婷婷久草| 色婷婷免费观看| 激情美女五月天激情在线| 丁香婷婷月| 成人国产欧美大片一区| 亚州精品成人片| 亚洲色婷婷| 欧美日韩一区二区三区四区| 91丨九色丨大屁股| Av中文在线| 六月丁香久久| 五月天激情.com| 99色综合| 中文字幕综合色| 俺来也综合网精品一区| 丁香婷婷成人在线播放| 婷婷五月天精品| 999热这里只有美国精品| 哇嘎成人久久| 亚洲精品性色| 97超碰综合| www.九九婷婷| 久久这里这里有精品免费视频| 五月婷婷啪| 婷婷久草| 九九婷婷综合| 日韩欧美一级大黄网站| 六月丁香五月天| 丁香五月最新网址| 亚洲色情激情丁香五月| 97久久人人操| 人操91在线| 狠狠色无码| 久久九九综合| 色五月开心久久网| 丁香五月狠狠综合欧美| 九九热中文| 色婷婷AⅤ| 五月丁香婷中文| 九九99久久| 九九99九九99九九99视频网| 综合久久五月天| 日本不卡一区二区三区| 国产成人av在线播放| 五月婷婷六月丁香在线| 4399无码视频| 亚洲综合网激情小说| 久久9精品| 亚洲超级碰| 色五月丁香六月婷婷| 无码人妻AV久久久一区二区三区| 爆乳熟妇一区二区三区爆乳照片| 六月 丁香 视频| httpwww色com日本| 色婷婷在线综合色播网| 六月激情网| 97视频久久| 久久久99免费视频| 91九色无码内射| 这里只有精彩亚洲视频推荐| 中字幕视频在线永久在线观看免费| 丁香婷婷五月色成人网站| 亚洲精品色| 中文字幕av网站| 五月婷婷开心综合| 偷拍丁香九月激情| 丁香五月天五码婷婷| 99热9| 最新热中文字幕| AV九九| 9l视频自拍9l九色成人| 4399亚洲视频| www.com任你艹| 婷婷色五月色| 大香蕉网 久久| 天天操综合网站| 丁香五月婷婷国产av| 国内精品玖玖| 五月天婷婷狂暴白浆| 久久九九蜜| 久久曰9| 国产日韩亚洲欧美在线观看| 天天干天天av天天射| 欧美色五月天| 91久久国产自产拍夜夜91久久精品文字>91麻豆精品国产 | 色五月婷婷基地| 婷婷丁香综合色AV| 99只有这里是精品| 日本天堂网站99| 深爱婷婷丁香五月激情| 婷婷伊人綜合| 婷婷色综合| 香蕉综合在线| 亚洲99热| 五月婷婷色播网| EEUSS鲁片一区二区三区| 亚洲精| 婷婷久综合| 久久人妻久久| 日91高清无玛| 99热精品无码| 99re思思精品视频在线观看| 丁香五月欧美婷婷综合| 五月色网| 五月婷婷亚洲色图| 婷婷丁香成人| 热99精品视频在线观看| 亚洲精品V天堂中文字幕| 婷婷五月AV| 国产亚洲色婷婷久久99精品91 www.riverspirits.org www.hnnun.com www.changh | 五月天堂在线| www热久久yy9| 久久丁香五月天| 久色姿源| 亚洲日比视频| 五月婷婷综合久久| 噜一噜免费视频| 五月激情四射网站| 婷婷丁香十月| 丁香五月亚洲激情婷婷射| 亚洲成人免费电影| 都市激情五月婷婷亚洲| 丁香久月婷| 伊人久久婷婷| 天天爽夜夜爽天天爽夜夜爽| 国产精品色婷婷99久久精品| 五月婷婷婷| av免费人人| 久婷久婷激情肉| 国产精品美女久久久久AV超清| 五月婷婷欲色| 成人视屏在线观看| 少妇高潮呻吟A片免费看软件 | 久久久免费精彩视频| 久久久网站| 日本色99网站| 六月丁香综合| 五月成人网天天| 激情综合网色五月| 少妇性BBB搡BBB爽爽爽电影| 婷婷五月另类网站| 天天射夜夜爽| 色婷小说| 久久99综合| 99色色色色| 六月婷婷六月天天在线免费| ztEJj| 久久五月天婷婷| 丁香婷婷色六月| 九九色色| 日本97在线看片| 99热只有| 久久精热| 高清无码一区二区三区四区| 999久久久国产精品| 变态 另类 在线 | 99热在线只有精品| 色天天久婷婷| 9 99免费视频| 婷婷丁香大香蕉| 99操99| 五月天色影院| tingting五月天亚洲| 99热精品观看| 色五月婷婷成人| 色久天| 夜夜操天天干| 九九热这里只有精品12| YJLZZJLZZ亚洲乱熟无码| 丁香婷婷婷| 五月色综合| 日韩综合久久| 久热视频这里只有精品| 99re久热只有精品6在线直播| 嫩草视频观看| 色域五月丁香| 色区久久| 婷婷性爱| 操97免费超级视频| 五月丁香六月婷婷无码| www.日日日.com| 色狠狠五月天| 色综合色综合色综合| www.9操| 五月天精品| 五月丁香亭亭操逼| 欧洲色| 操你av| 激情五月婷婷在线区| 久久久人妻人伦| 1024手机在线观看看片_日韩精品| 婷婷情色五月| 丁香五月狠狠在线观看| 99婷婷| 九九视频在线| 婷婷黄色| 欧美丁香五月97色| 色综合色色色| 婷婷射丁香| 深爱激情av| 九九热这里只有精品9| 久久久人妻不卡| 99精品久久| 91婷婷丁香五月天免费视频网站| 99热这里有精品首页10| www狠狠com| 一级性爱大片| 四色五月视频| 五月久久| 9久久久| 91免费试看| 大香蕉伊然在亚洲90| www.seqingwuyuetian| 色色婷婷综合| 亚洲综合五月天| AA片在线观看视频在线播放| 日欧一片内射VA在线影院| 91蜜桃婷婷狠狠久久综合9色| 色婷婷综合视频| 涩涩五月天| 国产精品国产成人国产三级| 亚洲天堂热| 国色天香成人网| 亚洲亚洲人成综合网络| 久久人人做人人妻人人玩精品va| 午夜不卡久久精品无码免费| 香蕉AV777XXX色综合一区| 婷婷综合中文字幕| 色啦啦视频| 96色婷婷| 久久日九九| 久久五月激情综合| 色欲色天天香综合| 99热99ai| 五月香蕉综合| 综合色综合| 六月丁香社区| 狠狠色噜噜狠狠| 欧美日综合| 日本天天色| 人妻丰满精品一区二区A片| 男男野外做爰全过程69| 激情玖玖综合网| 五月天堂色色| 五月婷婷久久久| 色婷婷五月在线| 五月丁香 六月婷婷a| 五月天婷婷影院影院| 99成人免费热视频| 色五月五月婷婷| 99欧美| 国内一级片| 天堂网操| 五月婷婷av| 亚洲婷婷五月草久| 婷婷涩五月天综合| 日韩精品一品二区三区的使用体验| 六月丁香av| 777精品久无码人妻蜜桃| 超碰cap| 色婷婷中文在线| 99riAV国产精品视频| 婷婷丁香五月激情综合站_久久五月丁香激情综合_开心五月综合激情综合五月_婷 | 欧美搡BBBBB摔BBBBB| 免费V片在线| 欧日韩成人| 婷婷五月天色综合翘| 99热这里只有在线| 丁香五月首页| 蜜桃人妻无码AV天堂三区| 色停停影院五月天| 天天色天天搡| 婷婷五月天亚洲精品| 久99热在线观看| 婷婷五月花| 一区中文字幕电影| 婷婷射图| 欧美综合五月丁香五月天| 亚洲AV人人操| 久久小说| 69久久99精品久久久久婷婷| 琪琪理论片| 99热这里只有精品免费| 色色热| 久久免费试看120秒| 婷婷丁香色五月天久久88| 人人视频色| www.色婷婷.com| 97色五月丁香婷婷| 日韩色色色99| 天天色天天日天天舔| 日韩成人免费电影| www.久久爱.c n| 玖玖伦理电影| 五月天伊人综合| 激情亚洲五月| 成人片在线播放| 天天色天天爱天天爱天天爱y| 久操婷婷| AVV黄| 久婷婷五月激情| 狼人婷婷综合| 日本波多野结衣视频| 色婷婷五月综合| 婷婷五月色天| 俺去也五月| 色久九| 狠狠操狠狠操| 免费无码毛片一区二区A片 | 婷婷久久五月| 丁香激情久久| 丁香成人视频| 午夜五月天| 综合www色| 婷婷伊人五月| 五月天综合视频| 五月婷婷|欧美| 五月色无码| 免费视频99| 九九99精品视频| 涩涩涩.com| 99久久国产宗和精品1上映| 丁香久久五月婷综合| 国产精品色婷婷AV综合色色| 51精品国自产在线| 国产操碰| 丁香久久综合| 精品一二三区久久AAA片| 亚洲精品成人| 任你搞网站| 热久91| 思思久日精品视频| 色五月激情五月| 五月婷婷在线短视频| 丁香花五月天激情| 热婷婷久| 婷婷开心久久| 99riAV成人在线视频| 亚洲色婷婷婷婷人人爽| 色色色99| 日韩成人中文字幕| 久久婷五月综合| 激情五月综合久久| 可似看的AV| 色婷婷aV四虎| 日韩在线婷婷五月天综合| 欧美顶级少妇做爰HD| 婷婷综合五月天激情| 色色性爱视频| 色六月丁香婷婷啪啪啪| 97色色色色色| 五月婷婷狠狠干| 久久婷婷五月综合色奶水99啪| 天天se在线视频| 伊人啪啪网| 色婷婷综合在线| 五月天综合影院| 国产三级在线播放| 激情五月天电影| 色五月激情综合网站| 五月丁花六月丁香综合| 成人网站高清无码| 伊人AV五月婷| 激情五月天婷婷色色色色色色色色色色色 | 天天天日天天天干| 综合色图婷婷| 三十路磁力链接| 色播jjjj| 五月婷六月天| 国内熟女黄色系列| 在线1青婷| 人操91在线| 久色激情| caop在线视频| 91性高潮久久久久久久久| 婷婷色激情网| 粉嫩AV久久一区二区三区| 天天日日天天| 久月久在线视频| www,色色色网站| 亚洲自拍天堂| 婷婷综合五月| 九九热这里有精品23| 精品无码久久久久久久久| 色五月婷婷啪啪五月| 欧美性生交XXXXX无码小说| 亚洲色 视频| 97色婷婷在线观看| 久久婷婷五月丁香网| 色欲人妻综合aaaaaaaa网| http:色情日本com| 26uuu亚洲欧美| 91啪啪啪啪| 亚洲另类在线观看| 蜘蛛女免费观看完整版高清电影| 农村熟妇高潮精品A片| 青草青青草| 五月天激情四射网站| 婷婷中文字幕| 色综合综合网| 色婷婷文字幕| 五月天桃色深爱网| 激情综合亚洲色婷婷五月| 色级婷婷| 色五月激情网| 婷婷婷五月天最新综合你懂的| av在线婷婷| 久99在线视频| 久久er九九| 国产97在线日韩亚洲女人被黑人巨大| 九九亚洲| 狠狠 婷婷| 91制片厂久久久国产电影| 婷婷九月亚洲| 97色五月天| 五月丁香日逼| 天天干天天日天天操| 天天狠狠色综合| 丁香五月777| 狠狠狠狠狠| 免费视频99| 婷婷丁香社区网| 一区二区三区四区牛| www.激情| 99热6这里只有精品|