一.前言
申明: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" Style="{StaticResource FIcon}" 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 Width="80" Height="80" Foreground="White" Background="Red" Margin="5" IsActive="{Binding IsChecked ,ElementName=cbActive2}" />
<core:BusyBox Width="30" Height="30" 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" Height="110" Width="260">
<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" Style="{StaticResource FIcon}" 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" Width="160" 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("已经完了?");
引用于
http://www.cnblogs.com/anding/p/5006279.html