背水一戰 Windows 10 之 控制項(控制項基類 - Control): 基礎知識, 焦點相關, 運行時獲取 ControlTemplate 和 DataTemplate 中的元素 ...
背水一戰 Windows 10 (76) - 控制項(控制項基類): Control - 基礎知識, 焦點相關, 運行時獲取 ControlTemplate 和 DataTemplate 中的元素
作者:webabcd
介紹
背水一戰 Windows 10 之 控制項(控制項基類 - Control)
- 基礎知識
- 焦點相關
- 運行時獲取 ControlTemplate 和 DataTemplate 中的元素
示例
1、演示 Control 的基礎知識
Controls/BaseControl/ControlDemo/Demo1.xaml
<Page x:Class="Windows10.Controls.BaseControl.ControlDemo.Demo1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:Windows10.Controls.BaseControl.ControlDemo" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="Orange"> <TextBox Name="textBox" Text="i am webabcd" TextWrapping="Wrap" AcceptsReturn="True" Margin="100" /> </Grid> </Page>
Controls/BaseControl/ControlDemo/Demo1.xaml.cs
/* * Control - Control(繼承自 UIElement, 請參見 /Controls/BaseControl/FrameworkElementDemo/) * Background - 背景 Brush * Foreground - 前景 Brush * BorderBrush - 邊框 Brush * BorderThickness - 邊框 Thickness * Padding - Padding * FontSize - 字型大小大小(單位:像素) * FontFamily - 首選字體,多個用“,”分隔,找不到第 1 個就用第 2 個,找不到第 2 個就用第 3 個,以此類推 * FontStretch - 字體的拉伸值(FontStretch 枚舉),預設值是 Normal(大部分字體都不支持這個屬性) * FontStyle - 字體樣式(FontStyle 枚舉) * Normal - 預設值 * Italic - 使用字體自帶的斜體 * Oblique - 通過程式讓正常字體傾斜(對於自身不帶斜體的字體可以使用此值讓字體傾斜) * FontWeight - 字體粗細(FontWeights 實體類),預設值是 Normal * CharacterSpacing - 用於設置字元間距 * 具體字元間隔像素計算公式如下:字體大小 * CharacterSpacing值 / 1000 = 字元間距像素值 * IsTextScaleFactorEnabled - 是否啟用文本自動放大功能(預設值是 true) * 在“設置”->“輕鬆使用”中可以調整文本縮放大小,IsTextScaleFactorEnabled 就是用於決定 TextBlock 顯示的文本是否跟著這個設置走 * HorizontalContentAlignment - 內容的水平對齊方式 * VerticalContentAlignment - 內容的垂直對齊方式 * IsEnabled - 是否可用 * IsEnabledChanged - IsEnabled 屬性的值發生變化時觸發的事件 * Template - 控制項模板,參見 /Controls/UI/ControlTemplate.xaml * * * 本例用於演示 Control 的基礎知識 */ using System; using Windows.UI; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media.Imaging; using Windows.UI.Text; namespace Windows10.Controls.BaseControl.ControlDemo { public sealed partial class Demo1 : Page { public Demo1() { this.InitializeComponent(); this.Loaded += Demo1_Loaded; } private void Demo1_Loaded(object sender, RoutedEventArgs e) { ImageBrush imageBrush = new ImageBrush(); imageBrush.ImageSource = new BitmapImage(new Uri("ms-appx:///Assets/hololens.jpg", UriKind.Absolute)); imageBrush.Stretch = Stretch.Fill; textBox.Background = imageBrush; // 關於各種類型的 Brush 請參見 /Drawing/Brush.xaml textBox.Foreground = new SolidColorBrush(Colors.DarkGreen); textBox.BorderBrush = new SolidColorBrush(Colors.Red); textBox.BorderThickness = new Thickness(0, 0, 0, 100); // 邊框的占用空間是完全是在 Control 內部的 textBox.Padding = new Thickness(20); textBox.FontSize = 24; textBox.FontFamily = new FontFamily("微軟雅黑,宋體"); textBox.FontStretch = FontStretch.Normal; textBox.FontStyle = FontStyle.Normal; textBox.FontWeight = FontWeights.Normal; textBox.CharacterSpacing = 100; textBox.IsTextScaleFactorEnabled = true; // 對於 TextBox 來說 HorizontalContentAlignment 和 VerticalContentAlignment 都是無效的 // 但是對於 Button 來說則可以通過 HorizontalContentAlignment 和 VerticalContentAlignment 來指定按鈕上文字的對齊方式 textBox.HorizontalContentAlignment = HorizontalAlignment.Center;// 無效,如果需要設置文字內容的水平對齊方式的話請使用 textBox.TextAlignment textBox.VerticalContentAlignment = VerticalAlignment.Center; // 無效 textBox.IsEnabledChanged += TextBox_IsEnabledChanged; textBox.IsEnabled = false; // 註:如果要修 IsEnabled = false 的樣式請查看名為 Disabled 的 VisualState textBox.IsEnabled = true; } private void TextBox_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e) { textBox.Text += Environment.NewLine; textBox.Text += $"textBox.IsEnabled, OldValue:{e.OldValue}, NewValue:{e.NewValue}"; } } }
2、演示 Control 的焦點相關的知識點
Controls/BaseControl/ControlDemo/Demo2.xaml
<Page x:Class="Windows10.Controls.BaseControl.ControlDemo.Demo2" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:Windows10.Controls.BaseControl.ControlDemo" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="Orange"> <StackPanel Name="stackPanel" Background="Blue" Margin="100"> <!-- 用於演示 TabIndex 和 IsTabStop --> <TextBox Name="textBox1" TabIndex="5" Margin="5" /> <TextBox Name="textBox2" TabIndex="3" Margin="5" /> <TextBox Name="textBox3" IsTabStop="False" TabIndex="4" Margin="5" /> <TextBox Name="textBox4" TabIndex="1" Margin="5" /> <TextBox Name="textBox5" TabIndex="2" Margin="5" /> <ComboBox Name="cmbTabNavigation" PlaceholderText="HorizontalAlignment" IsTabStop="False" SelectionChanged="cmbTabNavigation_SelectionChanged" Margin="5"> <ComboBoxItem IsSelected="True">Local</ComboBoxItem> <ComboBoxItem>Cycle</ComboBoxItem> <ComboBoxItem>Once</ComboBoxItem> </ComboBox> <!-- 用於演示 TabNavigation 1、Local - 當 focus 至 itemsControl 時,會逐一 focus 其內部的所有 Control 元素,然後退出 focus 2、Cycle - 當 focus 至 itemsControl 時,會逐一 focus 其內部的所有 Control 元素,然後再繼續無限迴圈 focus 其內部的所有 Control 元素 3、Once - 當 focus 至 itemsControl 時,只會 focus 其內部的第一個 Control 元素,然後退出 focus --> <ItemsControl Name="itemsControl" Margin="5" HorizontalAlignment="Left"> <ItemsControl.Items> <TextBox /> <TextBox /> <TextBox /> </ItemsControl.Items> </ItemsControl> <!-- 用於演示 UseSystemFocusVisuals 1、UseSystemFocusVisuals="False" 獲取焦點後,不會有任何效果,如果需要自定義獲取焦點後的效果的話請在控制項模板中設置 2、UseSystemFocusVisuals="True" 獲取焦點後,由系統繪製效果(我這裡測試的效果是,有一個虛線的邊框顯示) --> <Button Content="i am button 1" UseSystemFocusVisuals="False" Margin="5" /> <Button Content="i am button 2" UseSystemFocusVisuals="True" Margin="5" /> <Button Content="i am button 3" UseSystemFocusVisuals="False" Margin="5"> <Button.Template> <ControlTemplate TargetType="Button"> <Grid x:Name="RootGrid" Background="{TemplateBinding Background}"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="FocusStates"> <VisualState x:Name="Focused"> <VisualState.Setters> <Setter Target="border.BorderThickness" Value="5" /> </VisualState.Setters> </VisualState> <VisualState x:Name="Unfocused" /> <VisualState x:Name="PointerFocused" /> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Border x:Name="border" BorderBrush="Red" BorderThickness="0"> <ContentPresenter x:Name="ContentPresenter" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Content="{TemplateBinding Content}" ContentTransitions="{TemplateBinding ContentTransitions}" ContentTemplate="{TemplateBinding ContentTemplate}" Padding="{TemplateBinding Padding}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" AutomationProperties.AccessibilityView="Raw"/> </Border> </Grid> </ControlTemplate> </Button.Template> </Button> <!-- IsTemplateFocusTarget - 是否是控制項內用於獲取焦點的元素(附加屬性) --> <Button Content="i am button 4" Margin="5"> <Button.Template> <ControlTemplate TargetType="Button"> <Grid x:Name="RootGrid" Background="{TemplateBinding Background}"> <Border x:Name="border" BorderBrush="Red" BorderThickness="0"> <StackPanel> <ContentPresenter x:Name="ContentPresenter" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Content="{TemplateBinding Content}" ContentTransitions="{TemplateBinding ContentTransitions}" ContentTemplate="{TemplateBinding ContentTemplate}" Padding="{TemplateBinding Padding}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" AutomationProperties.AccessibilityView="Raw"/> <!-- Control.IsTemplateFocusTarget="True" - 代表此 Button 控制項用於獲取焦點的元素是此 TextBlock --> <TextBlock Control.IsTemplateFocusTarget="True" Text="IsTemplateFocusTarget" /> </StackPanel> </Border> </Grid> </ControlTemplate> </Button.Template> </Button> </StackPanel> </Grid> </Page>
Controls/BaseControl/ControlDemo/Demo2.xaml.cs
/* * Control - Control(繼承自 UIElement, 請參見 /Controls/BaseControl/FrameworkElementDemo/) * FocusState - 當前的焦點狀態(FocusState 枚舉) * Unfocused - 無焦點 * Pointer - 通過指針獲取的焦點 * Keyboard - 通過鍵盤獲取的焦點 * Programmatic - 通過 api 獲取的焦點 * bool Focus(FocusState value) - 設置焦點狀態 * TabIndex - Tab 鍵導航順序(按 tab 鍵正序導航;按 shift + tab 鍵倒序導航),預設值為 int.MaxValue * IsTabStop - 是否包含在 Tab 導航中(即是否可獲取到焦點) * TabNavigation - Tab 鍵導航至 Control 內部時的效果 * Local - 當 focus 至 Control 時,會逐一 focus 此 Control 內部的所有 Control 元素,然後退出 focus * Cycle - 當 focus 至 Control 時,會逐一 focus 此 Control 內部的所有 Control 元素,然後再繼續無限迴圈 focus 此 Control 內部的所有 Control 元素 * Once - 當 focus 至 Control 時,只會 focus 此 Control 內部的第一個 Control 元素,然後退出 focus * UseSystemFocusVisuals - 是否使用系統的焦點效果 * false - 在控制項模板中設置焦點效果 * true - 使用系統的焦點效果(我這裡測試的效果是,獲取焦點後會顯示一個虛線邊框) * IsTemplateFocusTarget - 是否是控制項內用於獲取焦點的元素(附加屬性) * GotFocus - 獲取焦點時觸發的事件(來自 UIElement) * LostFocus - 丟失焦點時觸發的事件(來自 UIElement) * * * 本例用於演示 Control 的焦點相關的知識點 */ using System; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Input; namespace Windows10.Controls.BaseControl.ControlDemo { public sealed partial class Demo2 : Page { public Demo2() { this.InitializeComponent(); this.Loaded += Demo2_Loaded; } private void Demo2_Loaded(object sender, RoutedEventArgs e) { textBox1.GotFocus += TextBox1_GotFocus; textBox2.GotFocus += TextBox2_GotFocus; textBox3.GotFocus += TextBox3_GotFocus; textBox4.GotFocus += TextBox4_GotFocus; textBox5.GotFocus += TextBox5_GotFocus; } private void TextBox1_GotFocus(object sender, RoutedEventArgs e) { textBox1.Text += textBox1.FocusState; } private void TextBox2_GotFocus(object sender, RoutedEventArgs e) { textBox2.Text += textBox2.FocusState; } private void TextBox3_GotFocus(object sender, RoutedEventArgs e) { textBox3.Text += textBox3.FocusState; } private void TextBox4_GotFocus(object sender, RoutedEventArgs e) { textBox4.Text += textBox4.FocusState; } // 這裡當 textBox5 獲取到焦點時,立刻指定 textBox2 獲取焦點,則會達到禁止 textBox5 獲取焦點的同時手動指定下一個焦點對象 // 如果只是禁止獲取焦點的話可以設置 IsTabStop 為 false private void TextBox5_GotFocus(object sender, RoutedEventArgs e) { textBox5.Text += textBox5.FocusState; // 設置為 FocusState.Unfocused 時會拋異常 bool success = textBox2.Focus(FocusState.Programmatic); } private void cmbTabNavigation_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (itemsControl != null) { itemsControl.TabNavigation = (KeyboardNavigationMode)Enum.Parse(typeof(KeyboardNavigationMode), (e.AddedItems[0] as ComboBoxItem).Content.ToString()); } } } }
3、演示如何在運行時獲取 ControlTemplate 和 DataTemplate 中的元素
Controls/BaseControl/ControlDemo/Demo3.xaml
<Page x:Class="Windows10.Controls.BaseControl.ControlDemo.Demo3" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:Windows10.Controls.BaseControl.ControlDemo" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" xmlns:common="using:Windows10.Common"> <Page.Resources> <!-- ControlTemplate - 控制項模板(是 xaml 語言使用的一種方案,其無法在 c# 中定義) --> <ControlTemplate x:Key="MyControlTemplate" TargetType="ContentControl"> <Grid x:Name="grid"> <ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" ContentTransitions="{TemplateBinding ContentTransitions}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/> </Grid> </ControlTemplate> <!-- DataTemplate - 數據模板(是 xaml 語言使用的一種方案,其無法在 c# 中定義) --> <DataTemplate x:DataType="common:Employee" x:Key="MyDataTemplate"> <TextBlock x:Name="textBlock" Text="{x:Bind Name}" /> </DataTemplate> </Page.Resources> <Grid Background="Transparent"> <StackPanel Margin="10 0 10 10"> <local:MyContentControl x:Name="myContentControl" DataContext="{x:Bind CurrentEmployee}" Template="{StaticResource MyControlTemplate}" ContentTemplate="{StaticResource MyDataTemplate}" /> </StackPanel> </Grid> </Page>
Controls/BaseControl/ControlDemo/Demo3.xaml.cs
/* * Control - Control(繼承自 UIElement, 請參見 /Controls/BaseControl/FrameworkElementDemo/) * GetTemplateChild() - 查找控制項模板中的指定名字的元素 * OnApplyTemplate() - 應用控制項模板時調用(來自 FrameworkElement) * * VisualTreeHelper - 可視化樹的實用工具類 * * * 本例用於演示如何在運行時獲取 ControlTemplate 和 DataTemplate 中的元素 */ using Windows.UI; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Media; using Windows10.Common; namespace Windows10.Controls.BaseControl.ControlDemo { public sealed partial class Demo3 : Page { public Employee CurrentEmployee { get; set; } = new Employee() { Name = "wanglei", Age = 36, IsMale = true }; public Demo3() { this.InitializeComponent(); myContentControl.Loaded += MyContentControl_Loaded; } private void MyContentControl_Loaded(object sender, RoutedEventArgs e) { // 通過 VisualTreeHelper 獲取可視化樹結構(藉此可以獲取數據模板中的元素) TextBlock textBlock = Helper.GetVisualChild<TextBlock>(myContentControl, "textBlock"); textBlock.FontSize = 48; } } public class MyContentControl : ContentControl { // override OnApplyTemplate() - 應用控制項模板時調用 protected override void OnApplyTemplate() { base.OnApplyTemplate(); // 在 OnApplyTemplate() 中通過 GetTemplateChild() 獲取控制項模板中的指定名字的元素 Grid grid = (Grid)GetTemplateChild("grid"); grid.Background = new SolidColorBrush(Colors.Orange); } } }
OK
[源碼下載]