<Window x:Class="PrograssBarNet.ProgressBarPrimary"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:PrograssBarNet"
mc:Ignorable="d"
Title="ProgressBarPrimary" Height="100" Width="900" WindowStartupLocation="CenterScreen" Background="Transparent" Foreground="Transparent"
WindowStyle="None" AllowsTransparency="True" Topmost="True">
<Window.Resources>
<ResourceDictionary>
<!--进度条-->
<SolidColorBrush x:Key="ProgressBar.Progress" Color="#FF2564F9"/>
<SolidColorBrush x:Key="ProgressBar.Background" Color="#FFB9B9B9"/>
<SolidColorBrush x:Key="ProgressBar.Border" Color="#FFDEDEDE"/>
<Style x:Key="BaseProgressBar" TargetType="{x:Type ProgressBar}">
<Setter Property="Foreground" Value="{StaticResource ProgressBar.Progress}"/>
<Setter Property="Background" Value="{StaticResource ProgressBar.Background}"/>
<Setter Property="BorderBrush" Value="{StaticResource ProgressBar.Border}"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Border.CornerRadius" Value="13"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ProgressBar}">
<Grid x:Name="TemplateRoot">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Determinate"/>
<VisualState x:Name="Indeterminate">
<Storyboard RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" Storyboard.TargetName="Animation">
<EasingDoubleKeyFrame KeyTime="0" Value="0.25"/>
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="0.25"/>
<EasingDoubleKeyFrame KeyTime="0:0:2" Value="0.25"/>
</DoubleAnimationUsingKeyFrames>
<PointAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransformOrigin)" Storyboard.TargetName="Animation">
<EasingPointKeyFrame KeyTime="0" Value="-0.5,0.5"/>
<EasingPointKeyFrame KeyTime="0:0:1" Value="0.5,0.5"/>
<EasingPointKeyFrame KeyTime="0:0:2" Value="1.5,0.5"/>
</PointAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="{TemplateBinding Border.CornerRadius}"/>
<Border x:Name="PART_Track" MinWidth="20" CornerRadius="{TemplateBinding Border.CornerRadius}"/>
<Grid x:Name="PART_Indicator" ClipToBounds="true" HorizontalAlignment="Left">
<Border x:Name="Indicator" MinWidth="20" Background="{TemplateBinding Foreground}" CornerRadius="{TemplateBinding Border.CornerRadius}"/>
<Border x:Name="Animation" MinWidth="20" Background="{TemplateBinding Foreground}"
CornerRadius="{TemplateBinding Border.CornerRadius}" RenderTransformOrigin="0.5,0.5">
<Border.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Border.RenderTransform>
<TextBlock HorizontalAlignment="Right" VerticalAlignment="Center" Foreground="#FFFFFF" FontSize="13"
Margin="0,0,10,0">
<Run Text="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Tag}"/>
<Run Text="%"/>
</TextBlock>
</Border>
<!--发光板-->
<Border ClipToBounds="True" >
<Border Width="{Binding PART_Track.Width}" Name="border1" Margin="-100,0">
<Border.Background>
<LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5" Opacity="0.4">
<GradientStop Color="{TemplateBinding Foreground}" Offset="0"/>
<GradientStop Color="#FFD8E4FB" Offset="0"/>
<GradientStop Color="{TemplateBinding Foreground}" Offset="1"/>
</LinearGradientBrush>
</Border.Background>
</Border>
</Border>
</Grid>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="Orientation" Value="Vertical">
<Setter Property="LayoutTransform" TargetName="TemplateRoot">
<Setter.Value>
<RotateTransform Angle="-90"/>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsIndeterminate" Value="true">
<Setter Property="Visibility" TargetName="Indicator" Value="Collapsed"/>
</Trigger>
<EventTrigger RoutedEvent="UserControl.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:2" To="1" Storyboard.TargetName="border1"
Storyboard.TargetProperty="Background.GradientStops[1].Offset"
RepeatBehavior="Forever"
AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</Window.Resources>
<Border CornerRadius="20" Background="Transparent" >
<ProgressBar Name="baseProgressBar" Height="40" Maximum="100" Value="0" Style="{DynamicResource BaseProgressBar}" Background="Transparent" Tag="0" />
</Border>
</Window>
2、在新的线程中启动并设置值
public partial class ProgressBarPrimary : Window
public ProgressBarPrimary()
InitializeComponent();
public void SetBarValue(double i)
Action<DependencyProperty, object> update = this.baseProgressBar.SetValue;
Dispatcher.Invoke(update, DispatcherPriority.Normal, new object[] { System.Windows.Controls.Primitives.RangeBase.ValueProperty, i });
Dispatcher.Invoke(update, DispatcherPriority.Normal, new object[] { System.Windows.Controls.Primitives.RangeBase.TagProperty, i });
public class ProgressBarHelper
public static ProgressBarHelper _ = new ProgressBarHelper();
private Thread thread;
public void Show()
thread = new Thread(() =>
var progressBar = new ProgressBarPrimary();
progressBar.Show();
for (int i = 0; i < 100; i++)
progressBar.SetBarValue(i);
Thread.Sleep(200);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
public void Close()
thread?.Abort();
3、进度根据计算得到的函数
double GetTagValue(double i)
return i == this.baseProgressBar.Maximum ? 100 : Math.Round(100 / this.baseProgressBar.Maximum * i);
4、刷新界面的方法,目前还没感觉到作用
void DoEvents()
var frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
new DispatcherOperationCallback(ExitFrames), frame);
Dispatcher.PushFrame(frame);
catch (InvalidOperationException)
private object ExitFrames(object frame)
((DispatcherFrame)frame).Continue = false;
return null;
/// <summary>
/// ProgressBarPrimary.xaml 的交互逻辑
/// </summary>
public partial class ProgressBarPrimary : Window
public ProgressBarPrimary(double maxMinum)
InitializeComponent();
this.baseProgressBar.Maximum = maxMinum;
public void SetBarValue(double i)
Action<DependencyProperty, object> update = this.baseProgressBar.SetValue;
Dispatcher.Invoke(update, DispatcherPriority.Normal, new object[] { System.Windows.Controls.Primitives.RangeBase.ValueProperty, i });
Dispatcher.Invoke(update, DispatcherPriority.Normal, new object[] { System.Windows.Controls.Primitives.RangeBase.TagProperty, GetTagValue(i) });
DoEvents();
double GetTagValue(double i)
return i == this.baseProgressBar.Maximum ? 100 : Math.Round(100 / this.baseProgressBar.Maximum * i);
void DoEvents()
var frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
new DispatcherOperationCallback(ExitFrames), frame);
Dispatcher.PushFrame(frame);
catch (InvalidOperationException)
private object ExitFrames(object frame)
((DispatcherFrame)frame).Continue = false;
return null;
/// <summary>
/// 进度条的帮助类
/// </summary>
public class ProgressBarHelper:IDisposable
public static ProgressBarHelper _ = new ProgressBarHelper();
public Thread thread;
public string PipeName = "PipesOfProgressBar";
/// <summary>
/// 显示进度条
/// </summary>
/// <param name="maxminum">最大进度值</param>
public void Show(double maxminum)
thread = new Thread(() =>
var progressBar = new ProgressBarPrimary(maxminum);
progressBar.Show();
var server = new NamedPipeServerStream(PipeName);
server.WaitForConnection();
StreamReader reader = new StreamReader(server);
double result = 0;
var line = reader.ReadLine();
if (double.TryParse(line, out result))
if (result <= maxminum)
progressBar.SetBarValue(result);
break;
break;
} while (result < maxminum);
reader.Close();
server.Disconnect();
Thread.Sleep(3000);
catch { }
finally { server.Dispose(); }
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true;
thread.Start();
/// <summary>
/// 关闭进度条
/// </summary>
public void Close()
if(thread!=null && thread.IsAlive)
int count = 0;//等待线程运行结束,最多等待3秒
while (thread.ThreadState != ThreadState.Stopped && count<=3000)
Thread.Sleep(100);
count += 100;
thread.Abort();
writer?.Close();
client?.Dispose();
NamedPipeClientStream client;
StreamWriter writer;
private bool disposedValue;
/// <summary>
/// 连接管道
/// </summary>
public void ConnectPipe()
client = new NamedPipeClientStream(PipeName);
client.Connect(10000);
writer = new StreamWriter(client);
/// <summary>
/// 循环向管道内写入值,如果input大于进度条的最大值,抛出异常
/// </summary>
/// <param name="input">进度条的Value</param>
public void Run(double input)
writer.WriteLine(input);
writer.Flush();
protected virtual void Dispose(bool disposing)
if (!disposedValue)
Close();
// TODO: 释放未托管的资源(未托管的对象)并重写终结器
// TODO: 将大型字段设置为 null
disposedValue = true;
//实现析构函数,使没有调用close 方法 或者dispose 方法时进度条会被关闭
// // TODO: 仅当“Dispose(bool disposing)”拥有用于释放未托管资源的代码时才替代终结器
~ProgressBarHelper()
// 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
Dispose(disposing: false);
public void Dispose()
// 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
Dispose(disposing: true);
GC.SuppressFinalize(this);
控制台程序调用方法
static void Main(string[] args)
ProgressBarHelper._.Show(50);
ProgressBarHelper._.ConnectPipe();
for (int i = 1; i <=50; i++)
ProgressBarHelper._.Run(i);
Thread.Sleep(100);
ProgressBarHelper._.Close();
//ProgressBarHelper._.Dispose();