WPF BackgroundWorker线程与进度的处理

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_33538554/article/details/53301153

简介:

        开发过程中经常遇到一些费时的操作界面,比如统计某个磁盘分区的文件夹或者文件数目,如果分区很大或者文件过多的话,处理不好就会造成“假死”的情况,或者报“线程间操作无效”的异常,为了解决这个问题,可以使用委托来处理,在.net2.0中还可以用BackgroundWorker类。BackgroundWorker类是.net 2.0里新增加的一个类,对于需要长时间操作而不需要用户长时间等待的情况可以使用这个类。

注意:

        确保在 DoWork 事件处理程序中不操作任何用户界面对象。而应该通过 ProgressChanged 和 RunWorkerCompleted 事件与用户界面进行通信。

案例:

        引用:System.dll       下载:http://download.csdn.net/detail/qq_33538554/9690615

源码:

----------------------MainWindow.xaml

<Windowxmlns:dxc="http://schemas.devexpress.com/winfx/2008/xaml/charts"  
        x:Class="MobilePlugfest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MobilePlugfest"
        Height="300" Width="400"
        Background="Transparent"
        WindowStyle="None"
        AllowsTransparency="True">
    <Window.Resources>
        <ResourceDictionary>
            <!--引用进度条-->
            <local:ValueToProcessConverter x:Key="ValueToProcessConverter"/>
            <!--设置字体颜色-->
            <Style  x:Key="lab" TargetType="Label">
                <Setter Property="Foreground"Value="Red"></Setter>
            </Style>
            <!--系统提示字体颜色-->
            <Style  x:Key="TextBox" TargetType="TextBox">
                <Setter Property="Foreground"Value="Red"></Setter>
            </Style>
        </ResourceDictionary>
    </Window.Resources>
    <Grid>
        <!--设置窗体透明化-->
        <Border CornerRadius="5"BorderThickness="2" BorderBrush="White"Opacity="0.8">
            <Border.Effect>
                <DropShadowEffect ShadowDepth="0"Color="#FF414141"BlurRadius="8"/>
            </Border.Effect>
            <Border Background="Black"Opacity="0.5" CornerRadius="5">
                <!--系统提示框-->
                <TextBox  Name="txtLog"Background="Black"Height="250"Width="200"Margin="0,0,140,0"Style="{StaticResourceResourceKey=TextBox}"/>
            </Border>
        </Border>
        <!--进度条-->
        <ProgressBar Minimum="0"Maximum="100"Name="progressBar"Height="60"Width="60"Margin="200,0,0,180">
            <ProgressBar.Template>
                <ControlTemplate TargetType="ProgressBar">
                    <Border Background="{TemplateBindingValue,Converter={StaticResourceValueToProcessConverter},ConverterParameter=200}"
                            MouseLeftButtonDown="Border_MouseLeftButtonDown_1"/>
                </ControlTemplate>
            </ProgressBar.Template>
        </ProgressBar>
        <!--显示进度-->
        <Label Name="labTip" Style="{StaticResourcelab}"Height="100"Width="100"Margin="240,0,0,0"/>
    </Grid>
</Window>

----------------------MainWindow.xaml.cs

using SocketStd;//SocketStd
using System;
using System.Collections.Generic;
using System.ComponentModel;//BackgroundWorker
using System.Linq;
using System.Net;
using System.Net.Sockets;//TcpClient
using System.Text;
using System.Threading;//Thread
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Configuration;//ConfigurationManager

namespace MobilePlugfest
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        BackgroundWorker bgWorker;
        double scannedCount = Convert.ToDouble(ConfigurationManager.AppSettings["ScannedCount"]);
        int runningThreadCount = Convert.ToInt32(ConfigurationManager.AppSettings["RunningThreadCount"]);
        static int maxThread = Convert.ToInt32(ConfigurationManager.AppSettings["MaxThread"]);
        string host = ConfigurationManager.AppSettings["Host"].ToString();
        int port = Convert.ToInt32(ConfigurationManager.AppSettings["Port"]);
        int startIP = Convert.ToInt32(ConfigurationManager.AppSettings["StartIP"]);
        int endIP = Convert.ToInt32(ConfigurationManager.AppSettings["EndIP"]);
        string addresIP = ConfigurationManager.AppSettings["AddresIP"].ToString();

        public MainWindow()
        {
            bgWorker = new BackgroundWorker();
            //进度更新报告true
            bgWorker.WorkerReportsProgress = true;
            //异步取消true
            bgWorker.WorkerSupportsCancellation = true;
            //后台操作任务
            bgWorker.DoWork += DoWork_Handler;
            //后台操作进行时
            bgWorker.ProgressChanged += ProgressChanged_Handler;
            //后台操作完成
            bgWorker.RunWorkerCompleted += RunWorkerCompleted_Handler;
        }
        /// <summary>
        /// 进度条的点击事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Border_MouseLeftButtonDown_1(object sender, MouseButtonEventArgs e)
        {
            if (!bgWorker.IsBusy)
            {
                if (txtLog.Text != "") txtLog.Text = "";
                scannedCount = 0;
                //开始执行后台操作任务
                bgWorker.RunWorkerAsync();
            }
        }
        /// <summary>
        /// 后台操作任务
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DoWork_Handler(object sender, DoWorkEventArgs e)
        {
            double total = Convert.ToDouble(endIP - startIP + 1);
            for (int ip = startIP; ip <= endIP; ip++)
            {
                if (bgWorker.CancellationPending)
                {
                    e.Cancel = true;
                    break;
                }
                //IP地址段,默认:192.168.1.
                host = addresIP + ip.ToString();
                //带参数的多线程执行
                Thread thread = new Thread(() => Scan(host, port));
                thread.IsBackground = true;
                thread.Start();
                UpdateLabText(labTip, string.Format("正在扫描...\r\n第{0}台\r\n共{1}台\r\n进度:{2}%", scannedCount, total, Convert.ToInt32((scannedCount / total) * 100)));
                bgWorker.ReportProgress(Convert.ToInt32((scannedCount / total) * 100));
                runningThreadCount++;
                Thread.Sleep(10);//节省cpu资源
                //循环,直到某个线程工作完毕才启动另一新线程,也可以叫做推拉窗技术
                while (runningThreadCount >= maxThread) ;
            }
            //空循环,直到所有端口扫描完毕
            do
            {
                UpdateLabText(labTip, string.Format("正在扫描...\r\n第{0}台\r\n共{1}台\r\n进度:{2}%", scannedCount, total, Convert.ToInt32((scannedCount / total) * 100)));
                bgWorker.ReportProgress(Convert.ToInt32((scannedCount / total) * 100));
                Thread.Sleep(10);
            } while (runningThreadCount > 0);
        }
        /// <summary>
        /// 后台操作进行时
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ProgressChanged_Handler(object sender, ProgressChangedEventArgs e)
        {
            progressBar.Value = e.ProgressPercentage;
        }
        /// <summary>
        /// 后台操作完成
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void RunWorkerCompleted_Handler(object sender, RunWorkerCompletedEventArgs e)
        {
            labTip.Content = "扫描完成!";
        }
        /// <summary>
        /// 判断ip端口是否为开放状态
        /// </summary>
        /// <param name="m_host"></param>
        /// <param name="m_port"></param>
        public void Scan(string m_host, int m_port)
        {
            //高级的TcpClient类
            TcpClient tc = new TcpClient();
            //设置超时时间
            tc.SendTimeout = tc.ReceiveTimeout = 2000;
            try
            {
                //同步方法
                //IPAddress ip = IPAddress.Parse(host);
                //IPEndPoint IPendp = new IPEndPoint(ip, port);
                //tc.Connect(IPendp);

                //异步方法
                IAsyncResult oAsyncResult = tc.BeginConnect(m_host, m_port, null, null);
                //1000为超时时间
                oAsyncResult.AsyncWaitHandle.WaitOne(1000, true);
                if (tc.Connected)
                {
                    //如果连接上,证明此端口为开放状态
                    UpdateListBox(txtLog, m_host + ":" + m_port.ToString());
                }
            }
            catch (System.Net.Sockets.SocketException e)
            {
                //容错处理
                MessageBox.Show("Port {0} is closed", host.ToString());
                Console.WriteLine(e.Message);
            }
            finally
            {
                tc.Close();
                tc = null;
                scannedCount++;
                runningThreadCount--;
            }
        }

        delegate void SetLabCallback(System.Windows.Controls.Label lb, string text);
        /// <summary>
        /// 异步控件Label
        /// </summary>
        /// <param name="lb"></param>
        /// <param name="text"></param>
        public void UpdateLabText(System.Windows.Controls.Label lb, string text)
        {
            //InvokeRequired
            if (System.Threading.Thread.CurrentThread != lb.Dispatcher.Thread)
            {
                //控件只能由创建它的线程来访问。其他线程想访问必须调用该控件的Invoke方法。Invoke有两个参数,一个是委托方法,一个是参数值
                SetLabCallback d = new SetLabCallback(UpdateLabText);
                this.Dispatcher.Invoke(d, new object[] { lb, text });
            }
            else
            {
                lb.Content = text.Trim();
            }
        }

        delegate void SetListCallback(System.Windows.Controls.TextBox lstBox, string text);
        /// <summary>
        /// 异步控件TextBox
        /// </summary>
        /// <param name="lstBox"></param>
        /// <param name="text"></param>
        private void UpdateListBox(System.Windows.Controls.TextBox lstBox, string text)
        {
            if (System.Threading.Thread.CurrentThread != lstBox.Dispatcher.Thread)
            {
                SetListCallback d = new SetListCallback(UpdateListBox);
                this.Dispatcher.Invoke(d, new object[] { lstBox, text });
            }
            else
            {
                ShowMsg("系统提示:", "" + text.Trim() + "");
                txtLog.Text = SingleObject.GetSingle().LogString.ToString();
                txtLog.SelectionStart = txtLog.Text.Length;
                txtLog.SelectionLength = 0;
                txtLog.ScrollToEnd();
            }
        }
        /// <summary>
        /// 系统提示模板
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="msg"></param>
        private void ShowMsg(string sender, string msg)
        {
            string time = DateTime.Now.ToString("hh:mm:ss");
            SingleObject.GetSingle().LogString.AppendLine(time + "    " + sender);
            SingleObject.GetSingle().LogString.AppendLine(msg);
            SingleObject.GetSingle().LogString.AppendLine();
        }
    }
}

---------------------App.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup>
        <supportedRuntime version="v4.0"sku=".NETFramework,Version=v4.5" />
    </startup>
  <appSettings>
    <!--已扫描端口数目-->
    <add key ="ScannedCount" value="0"/>
    <!--正在运行的线程数目-->
    <add key ="RunningThreadCount" value ="0"/>
    <!--最大工作线程数-->
    <add key ="MaxThread" value ="100"/>
    <!--IP地址-->
    <add key ="Host" value ="null"/>
    <!--端口-->
    <add key ="Port" value ="80"/>
    <!--Ip数量-->
    <add key ="EndIP" value ="255"/>
    <!--Ip 192.168.1.1-->
    <add key ="StartIP" value ="1"/>
    <!--IP地址段-->
    <add key ="AddresIP" value ="192.168.1."/>
  </appSettings>
</configuration>

----------------------SingleObject.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace SocketStd
{
    public class SingleObject
    {
        private static SingleObject _singleObject;
        private SingleObject()
        {
            this.LogString = new StringBuilder();
            this.ConnectedSocket = new Dictionary<string,Socket>();
            this.IsMove = false;
            this.LastSendedFile = "";
        }
        public static SingleObject GetSingle()
        {
            if (_singleObject == null)
            {
                _singleObject = new SingleObject();
            }
            return _singleObject;
        }
        private StringBuilder_logString;
        public StringBuilderLogString
        {
            get
            {
                return _logString;
            }
            set
            {
                _logString = value;
            }
        }
        private Dictionary<string,Socket> _connectedSocket;
        public Dictionary<string,Socket> ConnectedSocket
        {
            get
            {
                return _connectedSocket;
            }
            set
            {
                _connectedSocket = value;
            }
        }
        private bool _isMove;
        public bool IsMove
        {
            get
            {
                return _isMove;
            }
            set
            {
                _isMove = value;
            }
        }
        private string _lastSendedFile;
        public string LastSendedFile
        {
            get
            {
                return _lastSendedFile;
            }
            set
            {
                _lastSendedFile = value;
            }
        }
    }
}
---------------------ValueToProcessConverter.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;

namespace MobilePlugfest
{
    public class ValueToProcessConverter:IValueConverter
    {
        private const double Thickness = 8;
        private const double Padding = 1;
        private const double WarnValue = 60;
        private const int SuccessRateFontSize = 34;
        private static readonly SolidColorBrush NormalBrush;
        private static readonly SolidColorBrush WarnBrush;
        private static readonly Typeface SuccessRateTypeface;

        private string percentString;
        private PointcenterPoint;
        private double radius;

        static ValueToProcessConverter()
        {
            NormalBrush=new SolidColorBrush(Colors.Green);
            WarnBrush=new SolidColorBrush(Colors.Red);
            SuccessRateTypeface=new Typeface(newFontFamily("MSYH"),newFontStyle(),newFontWeight(),newFontStretch());
        }

        public ValueToProcessConverter()
        {

        }

        public object Convert(objectvalue,Type targetType, objectparameter, System.Globalization.CultureInfoculture)
        {
            if (value is double && !string.IsNullOrEmpty((string)parameter))
            {
                double arg = (double)value;
                double width = double.Parse((string)parameter);
                radius = width / 2;
                centerPoint = new Point(radius, radius);
                return DrawBrush(arg, 100, radius, radius, Thickness, Padding);
            }
            else
            {
                throw new ArgumentException();
            }
        }

        public object ConvertBack(objectvalue,Type targetType, objectparameter, System.Globalization.CultureInfoculture)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// 根据角度获取坐标
        /// </summary>
        /// <param name="CenterPoint"></param>
        /// <param name="r"></param>
        /// <param name="angel"></param>
        /// <returns></returns>

        private PointGetPointByAngel(PointCenterPoint, double r, double angel)
        {
            Point p = new Point();
            p.X = Math.Sin(angel * Math.PI / 180) * r + CenterPoint.X;
            p.Y = CenterPoint.Y - Math.Cos(angel *Math.PI / 180) * r;
            return p;
        }

        /// <summary>
        /// 根据4个坐标画出扇形
        /// </summary>
        /// <param name="bigFirstPoint"></param>
        /// <param name="bigSecondPoint"></param>
        /// <param name="smallFirstPoint"></param>
        /// <param name="smallSecondPoint"></param>
        /// <param name="bigRadius"></param>
        /// <param name="smallRadius"></param>
        /// <param name="isLargeArc"></param>
        /// <returns></returns>

        private GeometryDrawingArcGeometry(PointbigFirstPoint,Point bigSecondPoint, Point smallFirstPoint, Point smallSecondPoint,doublebigRadius, double smallRadius, bool isLargeArc)
        {
            PathFigure pathFigure = new PathFigure { IsClosed = true };
            pathFigure.StartPoint = bigFirstPoint;
            pathFigure.Segments.Add(
              new ArcSegment
              {
                  Point = bigSecondPoint,
                  IsLargeArc = isLargeArc,
                  Size = new Size(bigRadius, bigRadius),
                  SweepDirection = SweepDirection.Clockwise
              });
            pathFigure.Segments.Add(new LineSegment { Point = smallSecondPoint });
            pathFigure.Segments.Add(
             new ArcSegment
             {
                 Point = smallFirstPoint,
                 IsLargeArc = isLargeArc,
                 Size = new Size(smallRadius, smallRadius),
                 SweepDirection = SweepDirection.Counterclockwise
             });
            PathGeometry pathGeometry = new PathGeometry();
            pathGeometry.Figures.Add(pathFigure);
            return pathGeometry;
        }

        /// <summary>
        /// 根据当前值和最大值获取扇形
        /// </summary>
        /// <param name="value"></param>
        /// <param name="maxValue"></param>
        /// <returns></returns>

        private GeometryGetGeometry(doublevalue, double maxValue, double radiusX, double radiusY, double thickness, double padding)
        {
            bool isLargeArc = false;
            double percent = value / maxValue;
            percentString = string.Format("{0}%",Math.Round(percent * 100));
            double angel = percent * 360D;
            if (angel > 180) isLargeArc = true;
            double bigR = radiusX;
            double smallR = radiusX - thickness + padding;
            Point firstpoint = GetPointByAngel(centerPoint, bigR, 0);
            Point secondpoint = GetPointByAngel(centerPoint, bigR, angel);
            Point thirdpoint = GetPointByAngel(centerPoint, smallR, 0);
            Point fourpoint = GetPointByAngel(centerPoint, smallR, angel);
            return DrawingArcGeometry(firstpoint, secondpoint, thirdpoint, fourpoint, bigR, smallR, isLargeArc);
        }

        private void DrawingGeometry(DrawingContextdrawingContext,double value, doublemaxValue, double radiusX, double radiusY, double thickness, double padding)
        {
            if (value != maxValue)
            {
                SolidColorBrush brush;
                if (value < WarnValue)
                {
                    brush = WarnBrush;
                }
                else
                {
                    brush = NormalBrush;
                }
                drawingContext.DrawEllipse(null,newPen(newSolidColorBrush(Color.FromRgb(0xdd, 0xdf, 0xe1)), thickness), centerPoint, radiusX, radiusY);
                drawingContext.DrawGeometry(brush, newPen(), GetGeometry(value, maxValue, radiusX, radiusY, thickness, padding));
                FormattedText formatWords = new FormattedText(percentString,
                    CultureInfo.CurrentCulture,
                    FlowDirection.LeftToRight,
                    SuccessRateTypeface,
                    SuccessRateFontSize,
                    brush);
                Point startPoint = new Point(centerPoint.X - formatWords.Width / 2, centerPoint.Y - formatWords.Height / 2);
                drawingContext.DrawText(formatWords, startPoint);
            }
            else
            {
                drawingContext.DrawEllipse(null,newPen(NormalBrush, thickness), centerPoint, radiusX, radiusY);
                FormattedText formatWords = new FormattedText("100%",
                    CultureInfo.CurrentCulture,
                    FlowDirection.LeftToRight,
                    SuccessRateTypeface,
                    SuccessRateFontSize,
                    NormalBrush);
                Point startPoint = new Point(centerPoint.X - formatWords.Width / 2, centerPoint.Y - formatWords.Height / 2);
                drawingContext.DrawText(formatWords, startPoint);
            }
            drawingContext.Close();
        }

        /// <summary>
        /// 根据当前值和最大值画出进度条
        /// </summary>
        /// <param name="value"></param>
        /// <param name="maxValue"></param>
        /// <returns></returns>

        private VisualDrawShape(doublevalue, double maxValue, double radiusX, double radiusY, double thickness, double padding)
        {
            DrawingVisual drawingWordsVisual =newDrawingVisual();
            DrawingContext drawingContext = drawingWordsVisual.RenderOpen();
            DrawingGeometry(drawingContext, value, maxValue, radiusX, radiusY, thickness, padding);
            return drawingWordsVisual;
        }

        /// <summary>
        ///根据当前值和最大值画出进度条
        /// </summary>
        /// <param name="value"></param>
        /// <param name="maxValue"></param>
        /// <returns></returns>

        private BrushDrawBrush(doublevalue, double maxValue, double radiusX, double radiusY, double thickness, double padding)
        {
            DrawingGroup drawingGroup = new DrawingGroup();
            DrawingContext drawingContext = drawingGroup.Open();
            DrawingGeometry(drawingContext, value, maxValue, radiusX, radiusY, thickness, padding);
            DrawingBrush brush = new DrawingBrush(drawingGroup);
            return brush;
        }
    }
}

截图:




猜你喜欢

转载自blog.csdn.net/qq_33538554/article/details/53301153
WPF
今日推荐