Frissítése UI és háttér szál kérdések

szavazat
0

Én kódoló egy osztály fájlok másolása és áthelyezése. Én emelése eseményeket, ha az aktuális fájl előrehaladását, és a teljes haladás változásokat. Amikor tesztelem a kódot a XP-s gépen jól működik, de amikor elindul az én Windows 7 64-bites gép, a jelenlegi fejlődés nem frissíti az UI helyesen. A jelenleg folyamatban Folyamatsáv csak egyre félig akkor kezdődik a következő fájlt, amely nem ugyanaz. A teljes haladás Folyamatsáv frissíti finom. Bármilyen ötletet, hogy ez miért történik?

EDIT: A Windows 7 gépen fut egy quad-core és az XP fut egy dual-core. Nem biztos, hogy lehet, hogy mi teszi a különbséget. Én csak egy amatőr így mentség a tudatlanság :)

EDIT: Code adunk (háttér)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Threading;
using System.Timers;
using Timer = System.Timers.Timer;

namespace nGenSolutions.IO
{
public class FileTransporter
{
    #region Delegates

    public delegate void CurrentFileChangedEventHandler(string fileName);

    public delegate void CurrentProgressChangedEventHandler(int      percentComplete);

    public delegate void CurrentWriteSpeedUpdatedEventHandler(long bytesPerSecond);

    public delegate void TotalProgressChangedEventHandler(int percentComplete);

    public delegate void TransportCompleteEventHandler(FileTransportResult result);

    #endregion

    private readonly List<string> _destinationFiles = new List<string>();
    private readonly List<string> _sourceFiles = new List<string>();

    private long _bytesCopiedSinceInterval;
    private FileTransportResult _result;

    private Timer _speedTimer;
    private long _totalDataLength;

    private BackgroundWorker _worker;

    public bool TransportInProgress { get; private set; }

    public event CurrentFileChangedEventHandler CurrentFileChanged;

    public event CurrentProgressChangedEventHandler CurrentProgressChanged;

    public event CurrentWriteSpeedUpdatedEventHandler CurrentWriteSpeedUpdated;

    public event TotalProgressChangedEventHandler TotalProgressChanged;

    public event TransportCompleteEventHandler TransportComplete;

    public void AddFile(string sourceFile, string destinationFile)
    {
        if (!File.Exists(sourceFile))
            throw new FileNotFoundException(The specified file does not exist!, sourceFile);

        var fileInfo = new FileInfo(sourceFile);

        _totalDataLength += fileInfo.Length;

        _sourceFiles.Add(sourceFile);
        _destinationFiles.Add(destinationFile);
    }

    public void BeginTransport()
    {
        // update the write speed every 3 seconds
        _speedTimer = new Timer {Interval = 3000};
        _speedTimer.Elapsed += SpeedTimerElapsed;

        _worker = new BackgroundWorker();
        _worker.DoWork += DoTransport;
        _worker.RunWorkerCompleted += WorkerCompleted;

        _worker.RunWorkerAsync();
        _speedTimer.Start();

        TransportInProgress = true;
    }

    private void SpeedTimerElapsed(object sender, ElapsedEventArgs e)
    {
        InvokeCurrentSpeedUpdated(_bytesCopiedSinceInterval);

        _bytesCopiedSinceInterval = 0;
    }

    private void WorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        TransportInProgress = false;
        InvokeTransportComplete(_result);
    }

    public void CancelTransport(bool rollbackChanges)
    {
        if (TransportInProgress == false)
            throw new InvalidOperationException(You tried to stop the transport before you started it!);

        _result = FileTransportResult.Cancelled;

        _worker.CancelAsync();

        while (_worker.IsBusy)
        {
            // wait for worker to die an 'orrible death
        }

        // TODO: rollback changes if requested
    }

    private void DoTransport(object sender, DoWorkEventArgs e)
    {
        long totalBytesCopied = 0;
        int totalPercentComplete = 0;

        for (int i = 0; i < _sourceFiles.Count; i++)
        {
            string sourceFile = _sourceFiles[i];
            string destinationFile = _destinationFiles[i];

            long currentFileLength = new FileInfo(sourceFile).Length;

            InvokeCurrentFileChanged(sourceFile);

            using (var sourceStream = new FileStream(sourceFile, FileMode.Open, FileAccess.Read))
            {
                using (var destinationStream = new FileStream(destinationFile, FileMode.Create, FileAccess.Write))
                {
                    using (var reader = new BinaryReader(sourceStream))
                    {
                        using (var writer = new BinaryWriter(destinationStream))
                        {
                            int lastPercentComplete = 0;

                            for (int j = 0; j < currentFileLength; j++)
                            {
                                writer.Write(reader.ReadByte());

                                totalBytesCopied += 1;
                                _bytesCopiedSinceInterval += 1;

                                int current = Convert.ToInt32((j/(double) currentFileLength)*100);
                                int total = Convert.ToInt32((totalBytesCopied/(double) _totalDataLength)*100);

                                // raise progress events every 3%
                                if (current%3 == 0)
                                {
                                    // only raise the event if the progress has increased
                                    if (current > lastPercentComplete)
                                    {
                                        lastPercentComplete = current;
                                        InvokeCurrentProgressChanged(lastPercentComplete);
                                    }
                                }

                                if (total%3 == 0)
                                {
                                    // only raise the event if the progress has increased
                                    if (total > totalPercentComplete)
                                    {
                                        totalPercentComplete = total;
                                        InvokeTotalProgressChanged(totalPercentComplete);
                                    }
                                }
                            }
                        }

                        InvokeCurrentProgressChanged(100);
                    }
                }
            }
        }

        InvokeTotalProgressChanged(100);
    }

    private void InvokeCurrentFileChanged(string fileName)
    {
        CurrentFileChangedEventHandler handler = CurrentFileChanged;

        if (handler == null) return;

        handler(fileName);
    }

    private void InvokeCurrentProgressChanged(int percentComplete)
    {
        CurrentProgressChangedEventHandler handler = CurrentProgressChanged;

        if (handler == null) return;

        handler(percentComplete);
    }

    private void InvokeCurrentSpeedUpdated(long bytesPerSecond)
    {
        CurrentWriteSpeedUpdatedEventHandler handler = CurrentWriteSpeedUpdated;

        if (handler == null) return;

        handler(bytesPerSecond);
    }

    private void InvokeTotalProgressChanged(int percentComplete)
    {
        TotalProgressChangedEventHandler handler = TotalProgressChanged;

        if (handler == null) return;

        handler(percentComplete);
    }

    private void InvokeTransportComplete(FileTransportResult result)
    {
        TransportCompleteEventHandler handler = TransportComplete;

        if (handler == null) return;

        handler(result);
    }
}

}

EDIT: Code adunk (GUI)

using System;
using System.IO;
using System.Windows.Forms;
using ExtensionMethods;
using nGenSolutions.IO;

namespace TestApplication
{
public partial class ProgressForm : Form
{
    public ProgressForm()
    {
        InitializeComponent();
    }

    private void ProgressForm_Load(object sender, EventArgs e)
    {
        var transporter = new FileTransporter();
        foreach (string fileName in Directory.GetFiles(C:\\Temp\\))
        {
            transporter.AddFile(fileName, C:\\ + Path.GetFileName(fileName));
        }

        transporter.CurrentFileChanged += transporter_CurrentFileChanged;
        transporter.CurrentProgressChanged += transporter_CurrentProgressChanged;
        transporter.TotalProgressChanged += transporter_TotalProgressChanged;
        transporter.CurrentWriteSpeedUpdated += transporter_CurrentWriteSpeedUpdated;
        transporter.TransportComplete += transporter_TransportComplete;

        transporter.BeginTransport();
    }

    void transporter_TransportComplete(FileTransportResult result)
    {
        Close();
    }

    void transporter_CurrentWriteSpeedUpdated(long bytesPerSecond)
    {
        double megaBytesPerSecond = (double)bytesPerSecond/1024000;

        currentSpeedLabel.SafeInvoke(x=> x.Text = string.Format(Transfer speed: {0:0.0} MB/s, megaBytesPerSecond));
    }

    private void transporter_TotalProgressChanged(int percentComplete)
    {
        totalProgressBar.SafeInvoke(x => x.Value = percentComplete);
    }

    private void transporter_CurrentProgressChanged(int percentComplete)
    {
        currentProgressBar.SafeInvoke(x => x.Value = percentComplete);
    }

    private void transporter_CurrentFileChanged(string fileName)
    {
        this.SafeInvoke(x => x.Text = string.Format(Current file: {0}, fileName));
    }
}

}

EDIT: SafeInvoke kódot adunk

public static void SafeInvoke<T>(this T @this, Action<T> action) where T : Control
    {
        if (@this.InvokeRequired)
        {
            @this.Invoke(action, new object[] {@this});
        }
        else
        {
            if (!@this.IsHandleCreated) return;

            if (@this.IsDisposed)
                throw new ObjectDisposedException(@this is disposed.);

            action(@this);
        }
    }
A kérdést 12/06/2011 12:54
a forrás felhasználó
Más nyelveken...                            


1 válasz

szavazat
1

Nos, ha transporter_CurrentProgressChanged kap megfelelő értékeket, a program megfelelően működik. Meg lehet próbálni, hogy adjunk néhány minimális Thread.Sleep hívást InvokeCurrentProgressChanged (talán 0 paraméter), ha haladást érték 100%, hogy UI esélyt frissíteni magát, de ebben az esetben csökkentse a program működését. Ez talán jobb, ha a program nem változott, mivel úgy működik, mint az várható volt, és a fő állapotsáv frissül.

Válaszolt 12/06/2011 14:14
a forrás felhasználó

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more