直接設定 Button.Background 為 ImageBrush 時,滑鼠懸停會觸發預設樣式覆蓋背景,導致圖片消失。解法是建立自訂 ControlTemplate 將圖片作為內容呈現,但隨之而來的新挑戰是:如何在後台程式碼中動態修改模板內部的元素 (如更換圖片來源)?
ControlTemplate 有獨立的命名範圍。需先取得模板實例,再呼叫 FindName 並指定 FrameworkElement 作為命名範圍擁有者 (通常是套用模板的控件本身)。
ControlTemplate 指定 x:Name (或 x:Key 放入 Resources)button.Template.FindName("internalElementName", button)<Button Name="btnSure" Click="btnSure_Click" Margin="10">
<Button.Template>
<ControlTemplate x:Name="ctSure">
<ContentControl>
<Image x:Name="imgWork" Source="/Oland.HSS.InHospital;component/Pictures/maintenance/1.png"/>
</ContentControl>
</ControlTemplate>
</Button.Template>
</Button>
private void Window_Loaded(object sender, RoutedEventArgs e) {
if (!IsInMaintenance) {
// 方式一:透過控件的 Template 屬性直接取得
ControlTemplate template = btnSure.Template; // 若 Template 為直接指定
// 方式二:若模板放在 Resources,用 TryFindResource
// ControlTemplate template = (ControlTemplate)this.TryFindResource("TemplateKey");
if (template != null) {
// 關鍵:第二個參數必須傳入套用模板的控件 (btnSure) 作為命名範圍擁有者
Image img = template.FindName("imgWork", btnSure) as Image;
if (img != null) {
img.Source = new BitmapImage(new Uri(@"../Pictures/maintenance/3.png", UriKind.Relative));
}
}
}
}
ControlTemplate、DataTemplate、Style 皆建立獨立命名範圍,FindName 必須指定正確的範圍擁有者。Loaded 事件前模板可能尚未建立視覺樹,呼叫 FindName 會回傳 null。確保在 Loaded 或之後執行。ControlTemplate (來自 Resources),FindName 會返回「最後套用該模板的控件」對應的元素,需謹慎使用。建議每個需動態修改的控件使用獨立模板實例 (直接寫在 Button.Template 內)。文中提到加入 Trigger Property="Button.IsPressed" 縮放動畫後,觸控螢幕需點擊兩次才觸發 Click。可能原因:
RenderTransform 縮放導致觸點座標偏移,導致第二次觸控落在視覺樹外。LayoutTransform 或縮小縮放比例,或在 TouchDown/TouchUp 手動處理。修改 ControlTemplate 內部元素的關鍵在於 正確取得命名範圍擁有者並呼叫 FindName。掌握此技巧,即可在保持自訂視覺外觀的同時,保有後台動態調整 UI 的彈性。