鼠标悬停在Window上时,下载速度很慢

时间:2014-10-08 16:23:51

标签: c# wpf networking ftp mouse

我有以下代码从FTP服务器下载一些文件: 编辑:我已经使用DotNet解决了这个问题,这是一个很好的FTP WPF库!

public partial class MainWindow
{
    DispatcherTimer dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
    private byte[] downloadedData;
    string FTPAddress = "ftp://ftp.cluster007.ovh.net";

    double currentBytes;
    double oldBytes;


    public MainWindow()
    {
        InitializeComponent();

        //  DispatcherTimer setup
        dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
        dispatcherTimer.Interval = new TimeSpan(0, 0, 1);


    }

    public static void DoEvents()
    {
        Application.Current.Dispatcher.Invoke(DispatcherPriority.Background,
            new Action(delegate { }));
    }

    private void dispatcherTimer_Tick(object sender, EventArgs e)
    {
        currentBytes = Dl_ProgressBar.Value;
        Dl_Speed.Content = "Vitesse : " + ((currentBytes - oldBytes) / 1000000).ToString("0.00") + " Mo/s";

        oldBytes = Dl_ProgressBar.Value;

        // Forcing the CommandManager to raise the RequerySuggested event
        CommandManager.InvalidateRequerySuggested();
    }

    private void Dl_Button_Click(object sender, RoutedEventArgs e)
    {

        downloadFile();
    }

    private void downloadFile()
    {

        downloadedData = new byte[0];

        try
        {

            //Create FTP request
            //Note: format is ftp://server.com/file.ext
            FtpWebRequest request = FtpWebRequest.Create(FTPAddress + "/" + filename) as FtpWebRequest;

            //Get the file size first (for progress bar)
            request.Method = WebRequestMethods.Ftp.GetFileSize;
            request.Credentials = new NetworkCredential(username, password);
            request.UsePassive = true;
            request.UseBinary = true;
            request.KeepAlive = true; //don't close the connection

            int dataLength = (int)request.GetResponse().ContentLength;

            Dl_Status.Content = "Téléchargement en cours...";
            DoEvents();

            //Now get the actual data
            request = FtpWebRequest.Create(FTPAddress + "/" + filename) as FtpWebRequest;
            request.Method = WebRequestMethods.Ftp.DownloadFile;
            request.Credentials = new NetworkCredential(username, password);
            request.UsePassive = true;
            request.UseBinary = true;
            request.KeepAlive = false; //close the connection when done

            //Set up progress bar
            Dl_ProgressBar.Value = 0;
            Dl_ProgressBar.Maximum = dataLength;

            //Streams
            FtpWebResponse response = request.GetResponse() as FtpWebResponse;
            Stream reader = response.GetResponseStream();

            //Download to memory
            //Note: adjust the streams here to download directly to the hard drive
            MemoryStream memStream = new MemoryStream();
            byte[] buffer = new byte[1024]; //downloads in chuncks
            dispatcherTimer.Start();            
            while (true)
            {
                DoEvents(); //prevent application from crashing
                int bytesRead = reader.Read(buffer, 0, buffer.Length);

                if (bytesRead == 0)
                {
                    //Nothing was read, finished downloading
                    Dl_ProgressBar.Value = Dl_ProgressBar.Maximum;
                    Dl_Percent.Content = "Progression : 100%";

                    DoEvents();
                    break;
                }
                else
                {
                    //Write the downloaded data
                    memStream.Write(buffer, 0, bytesRead);

                    //Update the progress bar
                    if (Dl_ProgressBar.Value + bytesRead <= Dl_ProgressBar.Maximum)
                    {
                        Dl_ProgressBar.Value += bytesRead;
                        Dl_Percent.Content = "Progression : " + ((Dl_ProgressBar.Value / 1000000000000000) * dataLength).ToString("0.00") + "%";
                        DoEvents();
                    }
                }
            }

            //Convert the downloaded stream to a byte array
            downloadedData = memStream.ToArray();

            //Clean up
            reader.Close();
            memStream.Close();
            response.Close();

            Dl_Status.Content = "Téléchargement terminé";
            DoEvents();
        }
        catch (Exception)
        {
            Dl_Status.Content = "Erreur de connexion au FTP";
        }
    }

}

我的问题是,当我将鼠标移到窗口上时,下载速度明显下降...... 它从3.70Mb / s变为2.20Mb / s。 当我将鼠标移出窗口时,没有问题,但当我超过它时,它会减慢速度,特别是当我做一些非常短的动作时,下载速度会达到0.20Mb / s 。 我试过使用Threads和Dispatcher,但它是一样的。

1 个答案:

答案 0 :(得分:3)

要回答您的具体问题,WPF Dispatcher使用优先级队列,Input级事件(如源于鼠标移动的事件)优先于Background级事件。您的DoEvents()方法会定期消耗Background优先级为DoEvents的所有事件的消息队列,因此当您将鼠标移到窗口上时,队列会填充要处理的输入事件。这意味着DoEvents()需要更长的时间才能返回,并且在您可以继续处理下载之前需要更长的时间。

也就是说,这是完成下载的可怕的方式;你应该从不在WPF中使用这种async黑客攻击;对C#的awaitBackgroundWorker功能进行一些研究(或者,如果这不是一个选项,Dispatcher)。您将在StackOverflow上找到许多关于如何执行异步下载的示例,而不必采用这种{{1}}技巧来保持UI响应。