WPF 的 Trigger 機制讓開發者在純 XAML 中實現「狀態驅動外觀」:當條件滿足時自動套用 Setter 集合,條件不再成立時自動復原。觸發器本質上是 Style、ControlTemplate、DataTemplate 或 FrameworkElement 的 Triggers 集合項目,三大類型分別針對不同屬性體系:
監聽 Dependency Property 值變化,WPF 內建變更通知機制使其效能極佳。適用於 IsMouseOver、IsFocused、IsPressed、Validation.HasError 等 UI 狀態屬性。
<Style x:Key="btnHover" TargetType="Button">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="RenderTransform">
<Setter.Value><RotateTransform Angle="10"/></Setter.Value>
</Setter>
<Setter Property="RenderTransformOrigin" Value="0.5,0.5"/>
<Setter Property="Background" Value="#FF0CC030"/>
</Trigger>
</Style.Triggers>
</Style>
驗證錯誤視覺化 是屬性觸發器經典應用:
<Style x:Key="validateTextBox" TargetType="TextBox">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="Background" Value="Red"/>
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
針對 非依賴屬性(POCO 類別屬性、ViewModel 屬性)透過 Binding 監聽。Binding.Path 指定屬性路徑,Value 指定比對值。
<Style TargetType="ListBoxItem">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Role}" Value="Admin">
<Setter Property="Foreground" Value="Red"/>
<Setter Property="FontWeight" Value="Bold"/>
</DataTrigger>
</Style.Triggers>
</Style>
此範例中 ListBoxItem 的 DataContext 為 User 物件,當 Role=="Admin" 時自動高亮。
不包含 Setter,而是包含 TriggerAction 集合(如 BeginStoryboard、ControlStoryboardAction、InvokeCommandAction)。適用於 Click、Loaded、MouseEnter 等 RoutedEvent。
<Button Content="Click Me" Name="myButton">
<Button.BitmapEffect>
<DropShadowBitmapEffect x:Name="shadow" Color="Black" ShadowDepth="0"/>
</Button.BitmapEffect>
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="shadow" Storyboard.TargetProperty="ShadowDepth" From="0" To="30" Duration="0:0:0.5" AutoReverse="True"/>
<DoubleAnimation Storyboard.TargetName="shadow" Storyboard.TargetProperty="Softness" From="0" To="1" Duration="0:0:0.5" AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
單一條件不足時,使用條件集合(邏輯 AND):
Condition Property="..." Value="..."(依賴屬性)。Condition Binding="..." Value="..."(CLR 屬性)。<Style x:Key="highlightBtn" TargetType="Button">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="#EEEEEE"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="Visibility" Value="Visible"/>
<Condition Property="IsEnabled" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="BorderBrush" Value="Red"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Foreground" Value="Red"/>
</MultiTrigger>
</Style.Triggers>
</Style>
按鈕同時 Visible 且 Enabled 時呈現紅色粗體邊框;停用時灰色背景。
WPF 無直接「呼叫方法」的 TriggerAction,但可透過 附加依賴屬性 + PropertyChangedCallback 間接實現:
public static readonly DependencyProperty DoSomethingProperty =
DependencyProperty.RegisterAttached("DoSomething", typeof(bool), typeof(MyBehaviors),
new PropertyMetadata(false, OnDoSomethingChanged));
static void OnDoSomethingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
if ((bool)e.NewValue) { /* 執行業務邏輯 */ }
}
XAML 中:
<Button local:MyBehaviors.DoSomething="{Binding IsChecked, ElementName=chkTrigger}" />
此模式常封裝為 Behavior (Blend SDK) 或 Attached Behavior,保持 MVVM 純粹性。
Style.Triggers 而非元素級 Triggers,促進復用。VisualStateManager (VSM) 管理狀態群組,工具支援更佳。DataTrigger 的 Binding 若路徑較深,考慮在 ViewModel 暴露單一布林屬性簡化。AutoReverse="True" 或提供對應 ExitActions,避免狀態殘留。