申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接。
本文主要有三种实现方式:
简单忙碌状态控件BusyBox;
Win8/win10效果忙碌状态控件ProgressRing;
弹出异步等待框WaitingBox;
二.简单忙碌状态控件BusyBox
效果图:
通过属性"IsActive"控制控件是否启用,后台C#代码:
/// <summary> /// BusyBox.xaml 的交互逻辑 /// </summary> public partial class BusyBox : UserControl { public static readonly DependencyProperty IsActiveProperty = DependencyProperty.Register("IsActive", typeof(bool), typeof(BusyBox), new PropertyMetadata(false)); /// <summary> /// 是否启用 /// </summary> public bool IsActive { get { return (bool)GetValue(IsActiveProperty); } set { SetValue(IsActiveProperty, value); } } static BusyBox() { DefaultStyleKeyProperty.OverrideMetadata(typeof(BusyBox), new FrameworkPropertyMetadata(typeof(BusyBox))); } }使用了一个字体图标,触发器中实现动画显示的控制,样式代码: <Style TargetType="{x:Type local:BusyBox}"> <Setter Property="Foreground" Value="{StaticResource TextForeground}"></Setter> <Setter Property="Width" Value="32"></Setter> <Setter Property="Height" Value="32"></Setter> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type local:BusyBox}"> <Grid VerticalAlignment="Center" HorizontalAlignment="Center" > <Viewbox Stretch="Uniform" VerticalAlignment="Center" HorizontalAlignment="Center"> <TextBlock Text="" x:Name="FIcon" FontSize="36" RenderTransformOrigin="0.5,0.5" Foreground="{TemplateBinding Foreground}"> <TextBlock.RenderTransform> <RotateTransform x:Name="TransFIcon" Angle="0"/> </TextBlock.RenderTransform> </TextBlock> </Viewbox> </Grid> <ControlTemplate.Triggers> <!--激活状态--> <Trigger Property="IsActive" Value="true"> <Setter Property="Visibility" Value="Visible" TargetName="FIcon"/> <Trigger.EnterActions> <BeginStoryboard > <Storyboard > <DoubleAnimation RepeatBehavior="Forever" Storyboard.TargetName="TransFIcon" Storyboard.TargetProperty="Angle" To="360" Duration="0:0:2.5"/> </Storyboard> </BeginStoryboard> </Trigger.EnterActions> <Trigger.ExitActions> <BeginStoryboard > <Storyboard > <DoubleAnimation RepeatBehavior="Forever" Storyboard.TargetName="TransFIcon" Storyboard.TargetProperty="Angle" To="0" Duration="0"/> </Storyboard> </BeginStoryboard> </Trigger.ExitActions> </Trigger> <!--非激活状态--> <Trigger Property="IsActive" Value="false"> <Setter Property="Visibility" Value="Collapsed" TargetName="FIcon"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style>使用示例: <CheckBox VerticalAlignment="Center" x:Name="cbActive2" IsChecked="True" Margin="5">IsActive</CheckBox> <core:BusyBox Foreground="White" Background="Red" Margin="5" IsActive="{Binding IsChecked ,ElementName=cbActive2}" /> <core:BusyBox Foreground="White" Background="Red" Margin="5" IsActive="{Binding IsChecked ,ElementName=cbActive2}" />
四.弹出异步等待框WaitingBox
使用的是一个模式窗体,异步执行传入的操作,实现的比较简单,没有做异常处理。另外一个缺陷就是没有支持取消操作。后台C#代码:
/// <summary> /// 简单等待框 /// </summary> public partial class WaitingBox : Window { public string Text { get { return this.txtMessage.Text; } set { this.txtMessage.Text = value; } } private Action _Callback; public WaitingBox(Action callback) { InitializeComponent(); this._Callback = callback; this.Loaded += WaitingBox_Loaded; } void WaitingBox_Loaded(object sender, RoutedEventArgs e) { this._Callback.BeginInvoke(this.OnComplate, null); } private void OnComplate(IAsyncResult ar) { this.Dispatcher.Invoke(new Action(() => { this.Close(); })); } /// <summary> /// 显示等待框,owner指定宿主视图元素,callback为需要执行的方法体(需要自己做异常处理)。 /// 目前等等框为模式窗体 /// </summary> public static void Show(FrameworkElement owner, Action callback, string mes = "有一种幸福,叫做等待...") { WaitingBox win = new WaitingBox(callback); Window pwin = Window.GetWindow(owner); win.Owner = pwin; win.Text = mes; var loc = owner.PointToScreen(new Point()); win.Left = loc.X + (owner.ActualWidth - win.Width) / 2; win.Top = loc.Y + (owner.ActualHeight - win.Height) / 2; win.ShowDialog(); } }样式代码: <Window x:Class="System.Windows.WaitingBox" x:Name="wb" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" AllowsTransparency="True" WindowStyle="None" WindowStartupLocation="Manual" ShowInTaskbar="False" Background="Transparent" Title="WaitingBox"> <Grid> <!--Background="{Binding Path=Background,ElementName=wb}"--> <Border Background="{StaticResource WaitingBoxBackground}" Opacity="0.89" CornerRadius="1" Effect="{StaticResource WindowDropShadow}"></Border> <StackPanel VerticalAlignment="Center" Orientation="Horizontal" HorizontalAlignment="Center" Margin="5"> <TextBlock Text="" x:Name="FIcon" FontSize="50" RenderTransformOrigin="0.5,0.5" Margin="3"> <TextBlock.RenderTransform> <RotateTransform x:Name="TransFIcon" Angle="0"/> </TextBlock.RenderTransform> </TextBlock> <TextBlock x:Name="txtMessage" Margin="2,10,15,10" VerticalAlignment="Center" TextWrapping="Wrap">Loading...</TextBlock> </StackPanel> </Grid> <Window.Triggers> <EventTrigger RoutedEvent="Window.Loaded"> <BeginStoryboard > <Storyboard > <DoubleAnimation RepeatBehavior="Forever" Storyboard.TargetName="TransFIcon" Storyboard.TargetProperty="Angle" To="360" Duration="0:0:2.5"/> </Storyboard> </BeginStoryboard> </EventTrigger> </Window.Triggers> </Window>
使用比较简单,示例: WaitingBox.Show(this, () => { System.Threading.Thread.Sleep(3000); },"正在玩命的加载,请稍后..."); var res = MessageBoxX.Question("已经完了?");
引用于
WPF自定义控件与样式(11)-等待/忙/正在加载状态-控件实现
,