diff --git a/Nuclex.Support (Xbox 360).csproj b/Nuclex.Support (Xbox 360).csproj index 9b9788f..435e336 100644 --- a/Nuclex.Support (Xbox 360).csproj +++ b/Nuclex.Support (Xbox 360).csproj @@ -118,6 +118,10 @@ ReverseComparer.cs + + + PartialStream.cs + RingMemoryStream.cs diff --git a/Nuclex.Support.csproj b/Nuclex.Support.csproj index 1095550..9aae330 100644 --- a/Nuclex.Support.csproj +++ b/Nuclex.Support.csproj @@ -100,6 +100,10 @@ ReverseComparer.cs + + + PartialStream.cs + RingMemoryStream.cs diff --git a/Source/IO/ChainStream.Test.cs b/Source/IO/ChainStream.Test.cs index f1e9fc4..48085d9 100644 --- a/Source/IO/ChainStream.Test.cs +++ b/Source/IO/ChainStream.Test.cs @@ -227,7 +227,7 @@ namespace Nuclex.Support.IO { [Test] public void TestPartitionedRead() { ChainStream chainer = chainTwoStreamsOfTenBytes(); - + ((MemoryStream)chainer.ChainedStreams[0]).Write( new byte[] { 1, 2, 3, 4, 5 }, 0, 5 ); @@ -310,7 +310,7 @@ namespace Nuclex.Support.IO { byte[] buffer = new byte[5]; int readByteCount = chainer.Read(buffer, 0, 3); - + Assert.AreEqual(3, readByteCount); Assert.AreEqual(new byte[] { 0, 9, 8, 0, 0 }, buffer); diff --git a/Source/IO/PartialStream.Test.cs b/Source/IO/PartialStream.Test.cs new file mode 100644 index 0000000..8328fa7 --- /dev/null +++ b/Source/IO/PartialStream.Test.cs @@ -0,0 +1,515 @@ +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2009 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +#if UNITTEST + +using System; +using System.IO; + +using NUnit.Framework; + +namespace Nuclex.Support.IO { + + /// Unit Test for the partial stream + [TestFixture] + public class PartialStreamTest { + + #region class TestStream + + /// Testing stream that allows specific features to be disabled + private class TestStream : Stream { + + /// Initializes a new test stream + /// Stream that will be wrapped + /// Whether to allow reading from the stream + /// Whether to allow writing to the stream + /// Whether to allow seeking within the stream + public TestStream( + Stream wrappedStream, bool allowRead, bool allowWrite, bool allowSeek + ) { + this.stream = wrappedStream; + this.readAllowed = allowRead; + this.writeAllowed = allowWrite; + this.seekAllowed = allowSeek; + } + + /// Whether data can be read from the stream + public override bool CanRead { + get { return this.readAllowed; } + } + + /// Whether the stream supports seeking + public override bool CanSeek { + get { return this.seekAllowed; } + } + + /// Whether data can be written into the stream + public override bool CanWrite { + get { return this.writeAllowed; } + } + + /// + /// Clears all buffers for this stream and causes any buffered data to be written + /// to the underlying device. + /// + public override void Flush() { + ++this.flushCallCount; + this.stream.Flush(); + } + + /// Length of the stream in bytes + public override long Length { + get { + enforceSeekAllowed(); + return this.stream.Length; + } + } + + /// Absolute position of the file pointer within the stream + /// + /// At least one of the chained streams does not support seeking + /// + public override long Position { + get { + enforceSeekAllowed(); + return this.stream.Position; + } + set { + enforceSeekAllowed(); + this.stream.Position = value; + } + } + + /// + /// Reads a sequence of bytes from the stream and advances the position of + /// the file pointer by the number of bytes read. + /// + /// Buffer that will receive the data read from the stream + /// + /// Offset in the buffer at which the stream will place the data read + /// + /// Maximum number of bytes that will be read + /// + /// The number of bytes that were actually read from the stream and written into + /// the provided buffer + /// + public override int Read(byte[] buffer, int offset, int count) { + enforceReadAllowed(); + return this.stream.Read(buffer, offset, count); + } + + /// Changes the position of the file pointer + /// + /// Offset to move the file pointer by, relative to the position indicated by + /// the parameter. + /// + /// + /// Reference point relative to which the file pointer is placed + /// + /// The new absolute position within the stream + public override long Seek(long offset, SeekOrigin origin) { + enforceSeekAllowed(); + return this.stream.Seek(offset, origin); + } + + /// Changes the length of the stream + /// New length the stream shall have + public override void SetLength(long value) { + enforceSeekAllowed(); + this.stream.SetLength(value); + } + + /// + /// Writes a sequence of bytes to the stream and advances the position of + /// the file pointer by the number of bytes written. + /// + /// + /// Buffer containing the data that will be written to the stream + /// + /// + /// Offset in the buffer at which the data to be written starts + /// + /// Number of bytes that will be written into the stream + public override void Write(byte[] buffer, int offset, int count) { + enforceWriteAllowed(); + this.stream.Write(buffer, offset, count); + } + + /// Number of times the Flush() method has been called + public int FlushCallCount { + get { return this.flushCallCount; } + } + + /// Throws an exception if reading is not allowed + private void enforceReadAllowed() { + if(!this.readAllowed) { + throw new NotSupportedException("Reading has been disabled"); + } + } + + /// Throws an exception if writing is not allowed + private void enforceWriteAllowed() { + if(!this.writeAllowed) { + throw new NotSupportedException("Writing has been disabled"); + } + } + + /// Throws an exception if seeking is not allowed + private void enforceSeekAllowed() { + if(!this.seekAllowed) { + throw new NotSupportedException("Seeking has been disabled"); + } + } + + /// Stream being wrapped for testing + private Stream stream; + /// whether to allow reading from the wrapped stream + private bool readAllowed; + /// Whether to allow writing to the wrapped stream + private bool writeAllowed; + /// Whether to allow seeking within the wrapped stream + private bool seekAllowed; + /// Number of times the Flush() method has been called + private int flushCallCount; + + } + + #endregion // class TestStream + + /// Tests whether the partial stream constructor is working + [Test] + public void TestConstructor() { + using(MemoryStream memoryStream = new MemoryStream()) { + memoryStream.SetLength(123); + PartialStream partialStream = new PartialStream(memoryStream, 23, 100); + Assert.AreEqual(100, partialStream.Length); + } + } + + /// + /// Verifies that the partial stream constructor throws an exception if + /// it's invoked with an invalid start offset + /// + [Test, ExpectedException(typeof(ArgumentException))] + public void TestThrowOnInvalidStartInConstructor() { + using(MemoryStream memoryStream = new MemoryStream()) { + memoryStream.SetLength(123); + PartialStream partialStream = new PartialStream(memoryStream, -1, 10); + Assert.AreNotEqual(partialStream.Length, partialStream.Length); + } + } + + /// + /// Verifies that the partial stream constructor throws an exception if + /// it's invoked with an invalid start offset + /// + [Test, ExpectedException(typeof(ArgumentException))] + public void TestThrowOnInvalidLengthInConstructor() { + using(MemoryStream memoryStream = new MemoryStream()) { + memoryStream.SetLength(123); + PartialStream partialStream = new PartialStream(memoryStream, 100, 24); + Assert.AreNotEqual(partialStream.Length, partialStream.Length); + } + } + + /// + /// Verifies that the partial stream constructor throws an exception if + /// it's invoked with a start offset on an unseekable stream + /// + [Test, ExpectedException(typeof(ArgumentException))] + public void TestThrowOnUnseekableStreamWithOffsetInConstructor() { + using(MemoryStream memoryStream = new MemoryStream()) { + memoryStream.SetLength(123); + TestStream testStream = new TestStream(memoryStream, true, true, false); + PartialStream partialStream = new PartialStream(testStream, 23, 100); + Assert.AreNotEqual(partialStream.Length, partialStream.Length); + } + } + + /// + /// Tests whether the CanRead property reports its status correctly + /// + [Test] + public void TestCanReadProperty() { + using(MemoryStream memoryStream = new MemoryStream()) { + TestStream yesStream = new TestStream(memoryStream, true, true, true); + TestStream noStream = new TestStream(memoryStream, false, true, true); + + Assert.IsTrue(new PartialStream(yesStream, 0, 0).CanRead); + Assert.IsFalse(new PartialStream(noStream, 0, 0).CanRead); + } + } + + /// + /// Tests whether the CanWrite property reports its status correctly + /// + [Test] + public void TestCanWriteProperty() { + using(MemoryStream memoryStream = new MemoryStream()) { + TestStream yesStream = new TestStream(memoryStream, true, true, true); + TestStream noStream = new TestStream(memoryStream, true, false, true); + + Assert.IsTrue(new PartialStream(yesStream, 0, 0).CanWrite); + Assert.IsFalse(new PartialStream(noStream, 0, 0).CanWrite); + } + } + + /// + /// Tests whether the CanSeek property reports its status correctly + /// + [Test] + public void TestCanSeekProperty() { + using(MemoryStream memoryStream = new MemoryStream()) { + TestStream yesStream = new TestStream(memoryStream, true, true, true); + TestStream noStream = new TestStream(memoryStream, true, true, false); + + Assert.IsTrue(new PartialStream(yesStream, 0, 0).CanSeek); + Assert.IsFalse(new PartialStream(noStream, 0, 0).CanSeek); + } + } + + /// + /// Tests whether the CompleteStream property returns the original stream + /// + [Test] + public void TestCompleteStreamProperty() { + using(MemoryStream memoryStream = new MemoryStream()) { + PartialStream partialStream = new PartialStream(memoryStream, 0, 0); + Assert.AreSame(memoryStream, partialStream.CompleteStream); + } + } + + /// Tests whether the Flush() method can be called + [Test] + public void TestFlush() { + using(MemoryStream memoryStream = new MemoryStream()) { + PartialStream partialStream = new PartialStream(memoryStream, 0, 0); + partialStream.Flush(); + } + } + + /// + /// Tests whether the Position property correctly reports the file pointer position + /// + [Test] + public void TestGetPosition() { + using(MemoryStream memoryStream = new MemoryStream()) { + memoryStream.SetLength(123); + PartialStream partialStream = new PartialStream(memoryStream, 23, 100); + + Assert.AreEqual(0, partialStream.Position); + + byte[] test = new byte[10]; + int bytesRead = partialStream.Read(test, 0, 10); + + Assert.AreEqual(10, bytesRead); + Assert.AreEqual(10, partialStream.Position); + + bytesRead = partialStream.Read(test, 0, 10); + + Assert.AreEqual(10, bytesRead); + Assert.AreEqual(20, partialStream.Position); + + } + } + + /// + /// Tests whether the Position property is correctly updated + /// + [Test] + public void TestSetPosition() { + using(MemoryStream memoryStream = new MemoryStream()) { + memoryStream.SetLength(123); + PartialStream partialStream = new PartialStream(memoryStream, 23, 100); + + Assert.AreEqual(0, partialStream.Position); + partialStream.Position = 7; + Assert.AreEqual(partialStream.Position, 7); + partialStream.Position = 14; + Assert.AreEqual(partialStream.Position, 14); + } + } + + /// + /// Tests whether the Position property throws an exception if the stream does + /// not support seeking. + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnGetPositionOnUnseekableStream() { + using(MemoryStream memoryStream = new MemoryStream()) { + TestStream testStream = new TestStream(memoryStream, true, true, false); + + PartialStream partialStream = new PartialStream(testStream, 0, 0); + Assert.AreEqual(-12345, partialStream.Position); + } + } + + /// + /// Tests whether the Position property throws an exception if the stream does + /// not support seeking. + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnSetPositionOnUnseekableStream() { + using(MemoryStream memoryStream = new MemoryStream()) { + TestStream testStream = new TestStream(memoryStream, true, true, false); + + PartialStream partialStream = new PartialStream(testStream, 0, 0); + partialStream.Position = 0; + } + } + + /// + /// Tests whether the Read() method throws an exception if the stream does + /// not support reading + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnReadFromUnreadableStream() { + using(MemoryStream memoryStream = new MemoryStream()) { + TestStream testStream = new TestStream(memoryStream, false, true, true); + PartialStream partialStream = new PartialStream(testStream, 0, 0); + + byte[] test = new byte[10]; + int bytesRead = partialStream.Read(test, 0, 10); + + Assert.AreNotEqual(bytesRead, bytesRead); + } + } + + /// + /// Tests whether the Seek() method of the partial stream is working + /// + [Test] + public void TestSeeking() { + using(MemoryStream memoryStream = new MemoryStream()) { + memoryStream.SetLength(20); + PartialStream partialStream = new PartialStream(memoryStream, 0, 20); + + Assert.AreEqual(7, partialStream.Seek(-13, SeekOrigin.End)); + Assert.AreEqual(14, partialStream.Seek(7, SeekOrigin.Current)); + Assert.AreEqual(11, partialStream.Seek(11, SeekOrigin.Begin)); + } + } + + /// + /// Tests whether the Seek() method throws an exception if an invalid + /// reference point is provided + /// + [Test, ExpectedException(typeof(ArgumentException))] + public void TestThrowOnInvalidSeekReferencePoint() { + using(MemoryStream memoryStream = new MemoryStream()) { + PartialStream partialStream = new PartialStream(memoryStream, 0, 0); + partialStream.Seek(1, (SeekOrigin)12345); + } + } + + /// + /// Verifies that the partial stream throws an exception if the attempt is + /// made to change the length of the stream + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnLengthChange() { + using(MemoryStream memoryStream = new MemoryStream()) { + PartialStream partialStream = new PartialStream(memoryStream, 0, 0); + partialStream.SetLength(123); + } + } + + /// + /// Tests whether the Read() method returns 0 bytes if the attempt is made + /// to read data from an invalid position + /// + [Test] + public void TestReadFromInvalidPosition() { + using(MemoryStream memoryStream = new MemoryStream()) { + memoryStream.SetLength(123); + + memoryStream.Position = 1123; + byte[] test = new byte[10]; + + Assert.AreEqual(0, memoryStream.Read(test, 0, 10)); + } + } + + /// Verifies that the Read() method is working + [Test] + public void TestReadFromPartialStream() { + using(MemoryStream memoryStream = new MemoryStream()) { + memoryStream.SetLength(123); + + memoryStream.Position = 100; + memoryStream.Write(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, 0, 10); + + PartialStream partialStream = new PartialStream(memoryStream, 95, 10); + + byte[] buffer = new byte[15]; + int bytesRead = partialStream.Read(buffer, 0, 15); + + Assert.AreEqual(10, bytesRead); + Assert.AreEqual( + new byte[] { 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 0, 0, 0, 0, 0 }, buffer + ); + } + } + + /// Verifies that the Write() method is working + [Test] + public void TestWriteToPartialStream() { + using(MemoryStream memoryStream = new MemoryStream()) { + memoryStream.SetLength(123); + + memoryStream.Position = 60; + memoryStream.Write(new byte[] { 11, 12, 13, 14, 15 }, 0, 5); + + PartialStream partialStream = new PartialStream(memoryStream, 50, 15); + partialStream.Position = 3; + partialStream.Write(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, 0, 10); + + byte[] buffer = new byte[17]; + memoryStream.Position = 49; + int bytesRead = memoryStream.Read(buffer, 0, 17); + + Assert.AreEqual(17, bytesRead); + Assert.AreEqual( + new byte[] { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 14, 15, 0 }, + buffer + ); + } + } + + /// + /// Verifies that an exception is thrown if the Write() method of the partial stream + /// is attempted to be used to extend the partial stream's length + /// + [Test, ExpectedException(typeof(NotSupportedException))] + public void TestThrowOnExtendPartialStream() { + using(MemoryStream memoryStream = new MemoryStream()) { + memoryStream.SetLength(25); + + PartialStream partialStream = new PartialStream(memoryStream, 10, 10); + partialStream.Position = 5; + partialStream.Write(new byte[] { 1, 2, 3, 4, 5, 6 }, 0, 6); + } + } + + } + +} // namespace Nuclex.Support.IO + +#endif // UNITTEST diff --git a/Source/IO/PartialStream.cs b/Source/IO/PartialStream.cs new file mode 100644 index 0000000..a9f8e6f --- /dev/null +++ b/Source/IO/PartialStream.cs @@ -0,0 +1,264 @@ +#region CPL License +/* +Nuclex Framework +Copyright (C) 2002-2009 Nuclex Development Labs + +This library is free software; you can redistribute it and/or +modify it under the terms of the IBM Common Public License as +published by the IBM Corporation; either version 1.0 of the +License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +IBM Common Public License for more details. + +You should have received a copy of the IBM Common Public +License along with this library +*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; + +namespace Nuclex.Support.IO { + + /// Wraps a stream and exposes only a limited region of its data + public class PartialStream : Stream { + + /// Initializes a new partial stream + /// + /// Stream the wrapper will make a limited region accessible of + /// + /// + /// Start index in the stream which becomes the beginning for the wrapper + /// + /// + /// Length the wrapped stream should report and allow access to + /// + public PartialStream(Stream stream, long start, long length) { + if(start < 0) { + throw new ArgumentException("Start index must not be less than 0", "start"); + } + + if(!stream.CanSeek) { + if(start != 0) { + throw new ArgumentException( + "The only valid start for unseekable streams is 0", "start" + ); + } + } else { + if(start + length > stream.Length) { + throw new ArgumentException( + "Partial stream exceeds end of full stream", "length" + ); + } + } + + this.stream = stream; + this.start = start; + this.length = length; + } + + /// Whether data can be read from the stream + public override bool CanRead { + get { return this.stream.CanRead; } + } + + /// Whether the stream supports seeking + public override bool CanSeek { + get { return this.stream.CanSeek; } + } + + /// Whether data can be written into the stream + public override bool CanWrite { + get { return this.stream.CanWrite; } + } + + /// + /// Clears all buffers for this stream and causes any buffered data to be written + /// to the underlying device. + /// + public override void Flush() { + this.stream.Flush(); + } + + /// Length of the stream in bytes + /// + /// The wrapped stream does not support seeking + /// + public override long Length { + get { return this.length; } + } + + /// Absolute position of the file pointer within the stream + /// + /// The wrapped stream does not support seeking + /// + public override long Position { + get { + if(!this.stream.CanSeek) { + throw makeSeekNotSupportedException("seek"); + } + + return this.position; + } + set { moveFilePointer(value); } + } + + /// + /// Reads a sequence of bytes from the stream and advances the position of + /// the file pointer by the number of bytes read. + /// + /// Buffer that will receive the data read from the stream + /// + /// Offset in the buffer at which the stream will place the data read + /// + /// Maximum number of bytes that will be read + /// + /// The number of bytes that were actually read from the stream and written into + /// the provided buffer + /// + /// + /// The wrapped stream does not support reading + /// + public override int Read(byte[] buffer, int offset, int count) { + if(!this.stream.CanRead) { + throw new NotSupportedException( + "Can't read: the wrapped stream doesn't support reading" + ); + } + + long remaining = this.length - this.position; + int bytesToRead = (int)Math.Min(count, remaining); + + if(this.stream.CanSeek) { + this.stream.Position = this.position + this.start; + } + int bytesRead = this.stream.Read(buffer, offset, bytesToRead); + this.position += bytesRead; + + return bytesRead; + } + + /// Changes the position of the file pointer + /// + /// Offset to move the file pointer by, relative to the position indicated by + /// the parameter. + /// + /// + /// Reference point relative to which the file pointer is placed + /// + /// The new absolute position within the stream + public override long Seek(long offset, SeekOrigin origin) { + switch(origin) { + case SeekOrigin.Begin: { + return Position = offset; + } + case SeekOrigin.Current: { + return Position += offset; + } + case SeekOrigin.End: { + return Position = (Length + offset); + } + default: { + throw new ArgumentException("Invalid seek origin", "origin"); + } + } + } + + /// Changes the length of the stream + /// New length the stream shall have + /// + /// Always, the stream chainer does not support the SetLength() operation + /// + public override void SetLength(long value) { + throw new NotSupportedException("Resizing partial streams is not supported"); + } + + /// + /// Writes a sequence of bytes to the stream and advances the position of + /// the file pointer by the number of bytes written. + /// + /// + /// Buffer containing the data that will be written to the stream + /// + /// + /// Offset in the buffer at which the data to be written starts + /// + /// Number of bytes that will be written into the stream + /// + /// The behavior of this method is as follows: If one or more chained streams + /// do not support seeking, all data is appended to the final stream in the + /// chain. Otherwise, writing will begin with the stream the current file pointer + /// offset falls into. If the end of that stream is reached, writing continues + /// in the next stream. On the last stream, writing more data into the stream + /// that it current size allows will enlarge the stream. + /// + public override void Write(byte[] buffer, int offset, int count) { + long remaining = this.length - this.position; + if(count > remaining) { + throw new NotSupportedException( + "Cannot extend the length of the partial stream" + ); + } + + if(this.stream.CanSeek) { + this.stream.Position = this.position + this.start; + } + this.stream.Write(buffer, offset, count); + + this.position += count; + } + + /// Stream being wrapped by the partial stream wrapper + public Stream CompleteStream { + get { return this.stream; } + } + + /// Moves the file pointer + /// New position the file pointer will be moved to + private void moveFilePointer(long position) { + if(!this.stream.CanSeek) { + throw makeSeekNotSupportedException("seek"); + } + + // Seemingly, it is okay to move the file pointer beyond the end of + // the stream until you try to Read() or Write() + this.position = position; + } + + /// + /// Constructs a NotSupportException for an error caused by the wrapped + /// stream having no seek support + /// + /// Action that was tried to perform + /// The newly constructed NotSupportedException + private static NotSupportedException makeSeekNotSupportedException(string action) { + return new NotSupportedException( + string.Format( + "Can't {0}: the wrapped stream does not support seeking", + action + ) + ); + } + + /// Streams that have been chained together + private Stream stream; + /// Start index of the partial stream in the wrapped stream + private long start; + /// Zero-based position of the partial stream's file pointer + /// + /// If the stream does not support seeking, the position will simply be counted + /// up until it reaches . + /// + private long position; + /// Length of the partial stream + private long length; + + + } + +} // namespace Nuclex.Support.IO diff --git a/Source/Scheduling/OperationQueue.cs b/Source/Scheduling/OperationQueue.cs index 7546324..7155fc5 100644 --- a/Source/Scheduling/OperationQueue.cs +++ b/Source/Scheduling/OperationQueue.cs @@ -119,10 +119,10 @@ namespace Nuclex.Support.Scheduling { copy(this, eventArguments); } - /// Prepares the current operation and calls its Begin() method + /// Prepares the current operation and calls its Start() method /// /// This subscribes the queue to the events of to the current operation - /// and launches the operation by calling its Begin() method. + /// and launches the operation by calling its Start() method. /// private void startCurrentOperation() { OperationType operation = this.children[this.currentOperationIndex].Transaction; @@ -168,8 +168,8 @@ namespace Nuclex.Support.Scheduling { /// Called when the current executing operation ends /// Operation that ended - /// Not used - private void asyncOperationEnded(object sender, EventArgs e) { + /// Not used + private void asyncOperationEnded(object sender, EventArgs arguments) { // Unsubscribe from the current operation's events and update the // accumulating progress counter @@ -196,16 +196,17 @@ namespace Nuclex.Support.Scheduling { /// Called when currently executing operation makes progress /// Operation that has achieved progress - /// Not used - private void asyncOperationProgressChanged(object sender, ProgressReportEventArgs e) { + /// Not used + private void asyncOperationProgressChanged( + object sender, ProgressReportEventArgs arguments + ) { // Determine the completed weight of the currently executing operation - float currentOperationCompletedWeight = - e.Progress * this.children[this.currentOperationIndex].Weight; + float operationWeight = this.children[this.currentOperationIndex].Weight; + float operationCompletedWeight = arguments.Progress * operationWeight; // Build the total normalized amount of progress for the queue - float progress = - (this.completedWeight + currentOperationCompletedWeight) / this.totalWeight; + float progress = (this.completedWeight + operationCompletedWeight) / this.totalWeight; // Done, we can send the actual progress to any event subscribers OnAsyncProgressChanged(progress);