背水一戰 Windows 10 之 控制項(控制項基類): CoreDispatcher, 依賴屬性的設置與獲取, 依賴屬性的變化回調 ...
背水一戰 Windows 10 (67) - 控制項(控制項基類): DependencyObject - CoreDispatcher, 依賴屬性的設置與獲取, 依賴屬性的變化回調
作者:webabcd
介紹
背水一戰 Windows 10 之 控制項(控制項基類)
- CoreDispatcher
- 依賴屬性的設置與獲取
- 依賴屬性的變化回調
示例
1、演示 CoreDispatcher 的應用
Controls/BaseControl/DependencyObjectDemo/CoreDispatcherDemo.xaml
<Page x:Class="Windows10.Controls.BaseControl.DependencyObjectDemo.CoreDispatcherDemo" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:Windows10.Controls.BaseControl.DependencyObjectDemo" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="Transparent"> <StackPanel Margin="10 0 10 10"> <TextBlock Name="lblMsg1" Margin="5" /> <TextBlock Name="lblMsg2" Margin="5" /> <TextBlock Name="lblMsg3" Margin="5" /> </StackPanel> </Grid> </Page>
Controls/BaseControl/DependencyObjectDemo/CoreDispatcherDemo.xaml.cs
/* * DependencyObject - 依賴對象(可以在 DependencyObject 上定義 DependencyProperty) * Dispatcher - 獲取 CoreDispatcher 對象 * * * CoreDispatcher - 核心調度器 * CurrentPriority - 獲取或設置當前任務的優先順序(CoreDispatcherPriority 枚舉) * HasThreadAccess - 獲取一個值,用於說明當前線程是否可更新此 CoreDispatcher 線程上的 UI * RunAsync(), RunIdleAsync(), TryRunAsync(), TryRunIdleAsync() - 在此 CoreDispatcher 線程上使用指定的優先順序執行指定的方法(一般用於更新 CoreDispatcher 線程上的 UI) * ShouldYield() - 用於獲知當前任務隊列中是否存在更高優先順序的任務,或指定的優先順序及其以上的任務 * AcceleratorKeyActivated - 有按鍵操作時觸發的事件(針對 UIElement 的鍵盤事件監聽請參見:/Controls/BaseControl/UIElementDemo/KeyDemo.xaml) * * CoreDispatcherPriority - 任務優先順序枚舉(High, Normal, Low, Idle) * * 在 UWP 中優先順序從高到低的排序如下 * 1、本地代碼中的 SendMessage * 2、CoreDispatcherPriority.High * 3、CoreDispatcherPriority.Normal * 4、所有設備輸入消息 * 5、CoreDispatcherPriority.Low * 6、CoreDispatcherPriority.Idle(一般用於後臺任務) * * * 本例用於演示 DependencyObject 的 Dispatcher(CoreDispatcher 類型) 的應用 */ using System; using System.Threading; using Windows.UI.Core; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; namespace Windows10.Controls.BaseControl.DependencyObjectDemo { public sealed partial class CoreDispatcherDemo : Page { public CoreDispatcherDemo() { this.InitializeComponent(); this.Loaded += CoreDispatcherDemo_Loaded; // 監聽按鍵事件 Window.Current.CoreWindow.Dispatcher.AcceleratorKeyActivated += Dispatcher_AcceleratorKeyActivated; } private void CoreDispatcherDemo_Loaded(object sender, RoutedEventArgs e) { Timer timer = new Timer((p) => { // 當前線程是否可修改 CoreDispatcher 上的 UI if (base.Dispatcher.HasThreadAccess) { lblMsg1.Text = "相同線程 " + DateTime.Now.ToString("mm:ss"); } else { // 非 UI 線程通過 CoreDispatcher 更新 UI var ignored = base.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { lblMsg1.Text = "不同線程 " + DateTime.Now.ToString("mm:ss"); }); } }, null, TimeSpan.Zero, TimeSpan.FromSeconds(1)); DispatcherTimer dTimer = new DispatcherTimer(); dTimer.Interval = TimeSpan.FromSeconds(1); dTimer.Tick += (x, y) => { // 當前線程是否可修改 Dispatcher 上的 UI if (base.Dispatcher.HasThreadAccess) { lblMsg2.Text = "相同線程 " + DateTime.Now.ToString("mm:ss"); } else { // 非 UI 線程通過 CoreDispatcher 更新 UI var ignored = base.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { lblMsg2.Text = "不同線程 " + DateTime.Now.ToString("mm:ss"); }); } }; dTimer.Start(); } private void Dispatcher_AcceleratorKeyActivated(CoreDispatcher sender, AcceleratorKeyEventArgs args) { /* * AcceleratorKeyEventArgs - 按鍵事件參數 * EventType - 事件類型(比如 KeyDown, KeyUp 之類的,詳細參見 CoreAcceleratorKeyEventType 枚舉) * VirtualKey - 按鍵枚舉(比如 A, B, C, D, LeftControl 之類的,詳細參見 VirtualKey 枚舉) * KeyStatus - 按鍵的狀態(一個 CorePhysicalKeyStatus 類型的對象,有好多欄位,詳細參見文檔) */ lblMsg3.Text += $"EventType:{args.EventType}, VirtualKey:{args.VirtualKey}, IsExtendedKey:{args.KeyStatus.IsExtendedKey}, IsKeyReleased:{args.KeyStatus.IsKeyReleased}, IsMenuKeyDown:{args.KeyStatus.IsMenuKeyDown}, RepeatCount:{args.KeyStatus.RepeatCount}, ScanCode:{args.KeyStatus.ScanCode}, WasKeyDown:{args.KeyStatus.WasKeyDown}"; lblMsg3.Text += Environment.NewLine; // 屏蔽系統對按鍵的處理 args.Handled = true; } } }
2、演示依賴屬性的設置與獲取
Controls/BaseControl/DependencyObjectDemo/DependencyPropertyDemo.xaml
<Page x:Class="Windows10.Controls.BaseControl.DependencyObjectDemo.DependencyPropertyDemo" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:Windows10.Controls.BaseControl.DependencyObjectDemo" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="Transparent"> <StackPanel Margin="10 0 10 10"> <Rectangle Name="rect1" Height="50" Fill="Red" HorizontalAlignment="Left" Margin="5" /> <Rectangle Name="rect2" Height="50" Fill="Red" HorizontalAlignment="Left" Margin="5" /> <Rectangle Name="rect3" Height="50" Fill="Red" HorizontalAlignment="Left" Margin="5" /> <Rectangle Name="rect4" Width="400" Height="50" Fill="Red" Margin="5" /> <Button Name="button" Content="點我" Click="button_Click" Margin="5" /> <TextBlock Name="lblMsg" Margin="5" /> </StackPanel> </Grid> </Page>
Controls/BaseControl/DependencyObjectDemo/DependencyPropertyDemo.xaml.cs
/* * DependencyObject - 依賴對象(可以在 DependencyObject 上定義 DependencyProperty) * SetValue(DependencyProperty dp, object value) - 設置依賴屬性的值 * ClearValue(DependencyProperty dp) - 清除依賴屬性的值 * GetValue(DependencyProperty dp) - 獲取依賴屬性的當前值 * GetAnimationBaseValue(DependencyProperty dp) - 獲取依賴屬性的基值 * ReadLocalValue(DependencyProperty dp) - 獲取依賴屬性的本地值 * * * 本例用於演示 DependencyObject 的依賴屬性的設置與獲取 */ using System; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Media.Animation; using Windows.UI.Xaml.Shapes; namespace Windows10.Controls.BaseControl.DependencyObjectDemo { public sealed partial class DependencyPropertyDemo : Page { public DependencyPropertyDemo() { this.InitializeComponent(); this.Loaded += DependencyPropertyDemo_Loaded; } private void DependencyPropertyDemo_Loaded(object sender, RoutedEventArgs e) { // 直接設置依賴屬性(rect1.Width = 400; 其實調用的就是這個) rect1.SetValue(FrameworkElement.WidthProperty, 400); // 直接設置依賴屬性 rect2.SetValue(FrameworkElement.WidthProperty, 200); // 通過動畫的方式修改依賴屬性的值 SetRectWidth(rect2); // 通過 Style 的方式設置依賴屬性 Style style = new Style(); style.TargetType = typeof(Rectangle); Setter setter = new Setter(); setter.Property = Rectangle.WidthProperty; setter.Value = 200; style.Setters.Add(setter); rect3.Style = style; // 通過動畫的方式修改依賴屬性的值 SetRectWidth(rect3); // 清除依賴屬性的值 rect4.ClearValue(FrameworkElement.WidthProperty); } private void button_Click(object sender, RoutedEventArgs e) { DependencyProperty dp = FrameworkElement.WidthProperty; // 通過 SetValue 設置依賴屬性後,再通過 GetValue, GetAnimationBaseValue, ReadLocalValue 取出的值和設置的值都是一樣的 lblMsg.Text = $"rect1 GetValue:{rect1.GetValue(dp)}, GetAnimationBaseValue:{rect1.GetAnimationBaseValue(dp)}, ReadLocalValue:{rect1.ReadLocalValue(dp)}"; lblMsg.Text += Environment.NewLine; // 通過 SetValue 設置依賴屬性後,再通過動畫的方式修改其值 // GetValue - 獲取當前值 // GetAnimationBaseValue - 獲取基值,也就是動畫之前的值 // ReadLocalValue - 獲取本地值,即通過 SetValue 或者資源或者綁定設置的值 lblMsg.Text += $"rect2 GetValue:{rect2.GetValue(dp)}, GetAnimationBaseValue:{rect2.GetAnimationBaseValue(dp)}, ReadLocalValue:{rect2.ReadLocalValue(dp)}"; lblMsg.Text += Environment.NewLine; // 通過 Style 設置依賴屬性後,再通過動畫的方式修改其值 // GetValue - 獲取當前值 // GetAnimationBaseValue - 獲取基值,也就是動畫之前的值 // ReadLocalValue - 獲取本地值,即通過 SetValue 或者資源或者綁定設置的值(如果是通過其他方式,比如 Style 方式設置的值,則無本地值) lblMsg.Text += $"rect3 GetValue:{rect3.GetValue(dp)}, GetAnimationBaseValue:{rect3.GetAnimationBaseValue(dp)}, ReadLocalValue:{rect3.ReadLocalValue(dp)}"; lblMsg.Text += Environment.NewLine; // 通過 ClearValue 清除了依賴屬性的值,則再通過 GetValue, GetAnimationBaseValue, ReadLocalValue 均無法獲取到值 lblMsg.Text += $"rect4 GetValue:{rect4.GetValue(dp)}, GetAnimationBaseValue:{rect4.GetAnimationBaseValue(dp)}, ReadLocalValue:{rect4.ReadLocalValue(dp)}, ActualWidth:{rect4.ActualWidth}"; } private void SetRectWidth(Rectangle rect) { DoubleAnimation da = new DoubleAnimation(); da.EnableDependentAnimation = true; da.BeginTime = TimeSpan.Zero; da.To = 400; da.Duration = TimeSpan.FromSeconds(5); Storyboard.SetTarget(da, rect); Storyboard.SetTargetProperty(da, nameof(rect.Width)); Storyboard sb = new Storyboard(); sb.Children.Add(da); sb.Begin(); } } }
3、演示如何監聽依賴屬性的變化
Controls/BaseControl/DependencyObjectDemo/RegisterPropertyChangedCallbackDemo.xaml
<Page x:Class="Windows10.Controls.BaseControl.DependencyObjectDemo.RegisterPropertyChangedCallbackDemo" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:Windows10.Controls.BaseControl.DependencyObjectDemo" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid Background="Transparent"> <Grid.Resources> <BeginStoryboard x:Name="sb"> <Storyboard> <DoubleAnimation EnableDependentAnimation="True" Storyboard.TargetName="rect1" Storyboard.TargetProperty="Width" From="0" To="200" Duration="0:0:3"> </DoubleAnimation> </Storyboard> </BeginStoryboard> </Grid.Resources> <StackPanel Margin="10 0 10 10"> <Rectangle Name="rect1" Height="50" Fill="Red" HorizontalAlignment="Left" Margin="5" /> <TextBlock Name="lblMsg" Margin="5" /> </StackPanel> </Grid> </Page>
Controls/BaseControl/DependencyObjectDemo/RegisterPropertyChangedCallbackDemo.xaml.cs
/* * DependencyObject - 依賴對象(可以在 DependencyObject 上定義 DependencyProperty) * RegisterPropertyChangedCallback() - 為指定的依賴屬性註冊一個變化回調 * UnregisterPropertyChangedCallback() - 取消 RegisterPropertyChangedCallback() 的註冊 * * * 本例用於演示如何監聽 DependencyObject 的依賴屬性的變化 */ using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Navigation; using Windows.UI.Xaml.Shapes; namespace Windows10.Controls.BaseControl.DependencyObjectDemo { public sealed partial class RegisterPropertyChangedCallbackDemo : Page { private long _token = -1; public RegisterPropertyChangedCallbackDemo() { this.InitializeComponent(); } protected override void OnNavigatedTo(NavigationEventArgs e) { // 為 WidthProperty 註冊一個變化回調(返回值是一個 token 用於取消註冊用) _token = rect1.RegisterPropertyChangedCallback(Rectangle.WidthProperty, WidthChanged); base.OnNavigatedTo(e); } protected override void OnNavigatedFrom(NavigationEventArgs e) { // 為 WidthProperty 取消指定的變化回調(通過 token 來指定取消的是哪個變化回調) rect1.UnregisterPropertyChangedCallback(Rectangle.WidthProperty, _token); base.OnNavigatedFrom(e); } private void WidthChanged(DependencyObject sender, DependencyProperty prop) { double width = (double)sender.GetValue(prop); lblMsg.Text = $"width: {width}"; } } }
OK
[源碼下載]