訓練
屬性變更事件 (WPF .NET)
Windows Presentation Foundation (WPF) 定義了為回應屬性值變更而引發的數種事件。 屬性通常是相依性屬性。 事件本身可以是路由事件或標準通用語言執行平台 (CLR) 事件,視事件是否應該透過元素樹狀路由傳送,或只發生在屬性已變更的物件上。 當屬性變更只與屬性值變更的物件相關時,會套用後者情況。
本文會假設您具備相依性屬性的基本知識,而且已閱讀路由事件概觀。
並非所有報告屬性變更的事件都會明確識別為屬性已變更事件,不論是透過簽章模式或命名模式。 SDK 文件會交叉參考屬性與事件,並指出事件是否與屬性值變更直接相關。
某些事件會使用屬性已變更事件特有的事件資料類型和委派。 例如, RoutedPropertyChanged 和 DependencyPropertyChanged 事件各自有特定的簽章。 將在下列章節中討論這些事件類型。
RoutedPropertyChanged 事件具有 RoutedPropertyChangedEventArgs<T> 事件資料和 RoutedPropertyChangedEventHandler<T> 委派。 事件資料和委派都有泛型類型參數 T
。 當您定義處理常式時,您可以指定已變更屬性的實際類型。 事件資料包含 OldValue 和 NewValue 屬性,其執行階段類型與已變更的屬性相同。
名稱中 "Routed" 的部分表示已將屬性已變更的事件註冊為路由事件。 屬性變更路由事件的優點是,每當子元素屬性變更時,就會通知父元素。 這表示當控制項的任何複合組件的值變更時,控制項的最上層元素會收到屬性已變更事件。 例如,假設您建立包含 RangeBase 控制項的控制項,例如 Slider。 如果滑桿組件上的 Value 屬性值發生變更,您可以在父控制項而非該組件上處理該變更。
請避免使用屬性已變更事件處理常式來驗證屬性值,因為這不是大部分屬性已變更事件的設計意圖。 一般而言,會提供屬性已變更事件,以便回應程式碼其他邏輯區域中的值變更。 建議您從屬性已變更事件處理常式內再次變更屬性值,而且可能會根據您的處理程序實作造成非預期的遞迴。
如果您的屬性是自訂相依性屬性,或您使用已定義具現化程式碼的衍生類別,WPF 屬性系統有更好的方法來追蹤屬性變更。 這種方式是使用內建 CoerceValueCallback 和 PropertyChangedCallback 屬性系統回呼。 如需如何使用 WPF 屬性系統進行驗證和轉換的詳細資訊,請參閱相依性屬性回呼與驗證,以及自訂相依性屬性。
DependencyPropertyChanged 事件具有 DependencyPropertyChangedEventArgs 事件資料和 DependencyPropertyChangedEventHandler 委派。 這些事件是標準 CLR 事件,而不是路由事件。 DependencyPropertyChangedEventArgs
是特殊的事件資料報告類型,因為它並非衍生自 EventArgs,而且是結構而非類別。
DependencyPropertyChanged
事件的其中一個範例是 IsMouseCapturedChanged。 DependencyPropertyChanged
事件比 RoutedPropertyChanged
事件略為常見。
與 RoutedPropertyChanged 事件資料類似,DependencyPropertyChanged 事件資料包含 OldValue 和 NewValue 屬性。 基於先前所述的原因,請避免使用屬性已變更事件處理常式再次變更屬性值。
與屬性已變更事件密切相關的概念是屬性觸發程序。 屬性觸發程序是在樣式或範本內建立。 屬性觸發程序可讓您根據指派觸發程序的屬性值來建立條件式行為。
屬性觸發程序所作用的屬性必須是相依性屬性。 它可以 (而且通常) 是唯讀的相依性屬性。 如果控制項所公開的相依性屬性具有 "Is" 開頭的名稱,則該屬性很大機會至少有部分被設計為屬性觸發程序。 具有此命名的屬性通常是唯讀 Boolean 相依性屬性,其中屬性的主要案例是報告控制狀態。 如果控制狀態會影響即時 UI,則相依性屬性是個屬性觸發程序候選專案。
有些相依性屬性有專用的屬性已變更事件。 例如,IsMouseCaptured 有 IsMouseCapturedChanged 屬性已變更事件。 IsMouseCaptured
屬性是唯讀,而且其值是由輸入系統修改。 輸入系統會在每次即時變更時引發 IsMouseCapturedChanged
事件。
與 true 屬性已變更事件相比,屬性觸發程序有一些限制。
屬性觸發程序透過完全相符的邏輯運作,您可以在其中指定屬性名稱和將啟動觸發程序的特定值。 例如 <Setter Property="IsMouseCaptured" Value="true"> ... </Setter>
。 屬性觸發程序語法會將大部分的屬性觸發程序使用方式限制為 Boolean 個屬性,或採用專用列舉值的屬性。 可能值的範圍必須可管理,讓您可以為每個案例定義觸發程序。 有時只有特殊值會有屬性觸發程序存在,例如當項目計數達到零時。 無法將單一觸發程序設定為在屬性值偏離特定值 (例如零) 時啟動。 請考慮實作程式碼事件處理常式,或每當值不是零時從觸發程序狀態切換回的預設行為,而不是針對所有非零案例使用多個觸發程序。
屬性觸發程序語法類似於程式設計中的 "if" 陳述式。 如果觸發程序條件為 true,接著就會「執行」屬性觸發程序的「主體」。 屬性觸發程序的「主體」不是程式碼,而是標記。 該標記只能使用一或多個 Setter 元素,來設定要套用樣式或範本之物件的其他屬性。
當屬性觸發程序的「if」條件具有各種不同的可能值時,建議使用觸發程序外部的 Setter
將相同的屬性值設定為預設值。 如此一來,觸發程序內的 setter 會在觸發條件為 true
時具有優先順序,否則觸發程序外部的 Setter
將具有優先順序。
屬性觸發程序適用於一或多個外觀屬性應該根據相同元素上另一個屬性的狀態而變更的案例。
若要深入了解屬性觸發程序,請參閱設定樣式和範本。