/// <summary>Initializes a new unsubscribing transaction</summary> /// <param name="transactionToMonitor"> /// Transaction whose AsyncEnded event will be monitored to trigger /// the this transaction unsubscribing from the event. /// </param> public UnsubscribingTransaction(Transaction transactionToMonitor) { this.transactionToMonitor = transactionToMonitor; this.monitoredTransactionEndedDelegate = new EventHandler( monitoredTransactionEnded ); this.transactionToMonitor.AsyncEnded += this.monitoredTransactionEndedDelegate; }
/// <summary> /// Shows the progress reporter until the specified transaction has ended. /// </summary> /// <param name="windowTitle"> /// Text to be shown in the progress reporter's title bar /// </param> /// <param name="transaction"> /// Process for whose duration to show the progress reporter /// </param> public static void Track(string windowTitle, Transaction transaction) { // Small optimization to avoid the lengthy control creation when the background // process has already ended. This is an accepted race condition: If the process // finishes right after this line, it doesn't change the outcome, it just // causes the progress dialog to be constructed needlessly. if(transaction.Ended) return; // Open the form and let it monitor the transaction's state using(ProgressReporterForm theForm = new ProgressReporterForm()) { theForm.track(windowTitle, transaction); } }
/// <summary>Stops tracking the specified transaction</summary> /// <param name="transaction">Transaction to stop tracking</param> public void Untrack(Transaction transaction) { this.tracker.Untrack(transaction); }
/// <summary>Tracks the specified transaction in the tracking bar</summary> /// <param name="transaction">Transaction to be tracked</param> /// <param name="weight">Weight of this transaction in the total progress</param> public void Track(Transaction transaction, float weight) { this.tracker.Track(transaction, weight); }
/// <summary>Stops tracking the specified transaction</summary> /// <param name="transaction">Transaction to stop tracking</param> public void Untrack(Transaction transaction) { TrackingBarControl.Untrack(transaction); }
/// <summary>Tracks the specified transaction in the tracking bar</summary> /// <param name="transaction">Transaction to be tracked</param> /// <param name="weight">Weight of this transaction in the total progress</param> public void Track(Transaction transaction, float weight) { TrackingBarControl.Track(transaction, weight); }
/// <summary>Stops tracking the specified transaction</summary> /// <param name="transaction">Transaction that will no longer be tracked</param> public void Untrack(Transaction transaction) { }
/// <summary>Tracks the progress of the specified transaction</summary> /// <param name="transaction"> /// Transaction whose progress will be tracked /// </param> /// <param name="processIdentifier"> /// Identifier unique to the tracked background process. Can be null. /// </param> public void Track(Transaction transaction, object processIdentifier) { }
/// <summary>Mocks a subscriber for the events of a transaction</summary> /// <param name="transaction">Transaction to mock an event subscriber for</param> /// <returns>The mocked event subscriber</returns> private ITransactionGroupSubscriber mockSubscriber(Transaction transaction) { ITransactionGroupSubscriber mockedSubscriber = this.mockery.NewMock<ITransactionGroupSubscriber>(); transaction.AsyncEnded += new EventHandler(mockedSubscriber.Ended); (transaction as IProgressReporter).AsyncProgressChanged += new EventHandler<ProgressReportEventArgs>(mockedSubscriber.ProgressChanged); return mockedSubscriber; }
/// <summary>Mocks a subscriber for the events of a transaction</summary> /// <param name="transaction">Transaction to mock an event subscriber for</param> /// <returns>The mocked event subscriber</returns> private ITransactionSubscriber mockSubscriber(Transaction transaction) { ITransactionSubscriber mockedSubscriber = this.mockery.NewMock<ITransactionSubscriber>(); transaction.AsyncEnded += new EventHandler(mockedSubscriber.Ended); return mockedSubscriber; }
/// <summary> /// Shows the progress reporter until the specified transaction has ended. /// </summary> /// <param name="transaction"> /// Transaction for whose duration to show the progress reporter /// </param> public static void Track(Transaction transaction) { Track(null, transaction); }
/// <summary> /// Shows the progress reporter until the specified transaction has ended. /// </summary> /// <param name="windowTitle"> /// Text to be shown in the progress reporter's title bar /// </param> /// <param name="transaction"> /// Transaction for whose duration to show the progress reporter /// </param> private void track(string windowTitle, Transaction transaction) { // Set the window title if the user wants to use a custom one if(windowTitle != null) Text = windowTitle; // Only enable the cancel button if the transaction can be aborted this.abortReceiver = (transaction as IAbortable); this.cancelButton.Enabled = (this.abortReceiver != null); // Make sure the progress bar control has been created (otherwise, we've got // a chance that BeginInvoke() would fail if the first progress notification // arrived before we called ShowDialog()!) { IntPtr tempDummy = this.progressBar.Handle; } // Subscribe the form to the transaction it is supposed to monitor. // Careful: With the new design, this can cause the asyncEndedDelegate() // callback to be called immediately and synchronously! transaction.AsyncEnded += this.asyncEndedDelegate; IProgressReporter progressReporter = transaction as IProgressReporter; if(progressReporter != null) progressReporter.AsyncProgressChanged += this.asyncProgressChangedDelegate; // The transaction might have ended before this line was reached, if that's // the case, we don't show the dialog at all. if(!transaction.Ended) ShowDialog(); // We're done, unsubscribe from the transaction's events again progressReporter = transaction as IProgressReporter; if(progressReporter != null) { progressReporter.AsyncProgressChanged -= this.asyncProgressChangedDelegate; } transaction.AsyncEnded -= this.asyncEndedDelegate; }
/// <summary> /// Initializes a new transaction matcher that matches against /// the specified transaction /// </summary> /// <param name="toMatch">Transaction to match against</param> public TransactionMatcher(Transaction toMatch) { this.toMatch = toMatch; }
/// <summary>Stops tracking the specified background transaction</summary> /// <param name="transaction">Background transaction to stop tracking of</param> public void Untrack(Transaction transaction) { lock(this.trackedTransactions) { // Locate the object to be untracked in our collection int index; for(index = 0; index < this.trackedTransactions.Count; ++index) { bool same = ReferenceEquals( transaction, this.trackedTransactions[index].WeightedTransaction.Transaction ); if(same) { break; } } if(index == this.trackedTransactions.Count) { throw new ArgumentException("Specified transaction is not being tracked"); } // Remove and dispose the transaction the user wants to untrack { ObservedWeightedTransaction<Transaction> wrappedTransaction = this.trackedTransactions[index]; this.trackedTransactions.RemoveAt(index); wrappedTransaction.Dispose(); } // If the list is empty, then we're back in the idle state if(this.trackedTransactions.Count == 0) { this.totalWeight = 0.0f; // If we entered the idle state with this call, report the state change! setIdle(true); } else { // Rebuild the total weight from scratch. Subtracting the removed transaction's // weight would work, too, but we might accumulate rounding errors making the sum // drift slowly away from the actual value. float newTotalWeight = 0.0f; for(index = 0; index < this.trackedTransactions.Count; ++index) newTotalWeight += this.trackedTransactions[index].WeightedTransaction.Weight; this.totalWeight = newTotalWeight; recalculateProgress(); } } // lock }
/// <summary>Begins tracking the specified background transaction</summary> /// <param name="transaction">Background transaction to be tracked</param> /// <param name="weight">Weight to assign to this background transaction</param> public void Track(Transaction transaction, float weight) { // Add the new transaction into the tracking list. This has to be done // inside a lock to prevent issues with the progressUpdate callback, which could // access the totalWeight field before it has been updated to reflect the // new transaction added to the collection. lock(this.trackedTransactions) { bool wasEmpty = (this.trackedTransactions.Count == 0); if(transaction.Ended) { // If the ended transaction would become the only transaction in the list, // there's no sense in doing anything at all because it would have to be // thrown right out again. Only add the transaction when there are other // running transactions to properly sum total progress for consistency. if(!wasEmpty) { // Construct a new observation wrapper. This is done inside the lock // because as soon as we are subscribed to the events, we can potentially // receive them. The lock eliminates the risk of processing a progress update // before the transaction has been added to the tracked transactions list. this.trackedTransactions.Add( new ObservedWeightedTransaction<Transaction>( new WeightedTransaction<Transaction>(transaction, weight), this.asyncProgressUpdatedDelegate, this.asyncEndedDelegate ) ); } } else { // Not ended -- Transaction is still running // Construct a new transation observer and add the transaction to our // list of tracked transactions. ObservedWeightedTransaction<Transaction> observedTransaction = new ObservedWeightedTransaction<Transaction>( new WeightedTransaction<Transaction>(transaction, weight), this.asyncProgressUpdatedDelegate, this.asyncEndedDelegate ); this.trackedTransactions.Add(observedTransaction); // If this is the first transaction to be added to the list, tell our // owner that we're idle no longer! if(wasEmpty) { setIdle(false); } } // if transaction ended // This can be done after we registered the wrapper to our delegates because // any incoming progress updates will be stopped from the danger of a // division-by-zero from the potentially still zeroed totalWeight by the lock. this.totalWeight += weight; // All done, the total progress is different now, so force a recalculation and // send out the AsyncProgressUpdated event. recalculateProgress(); } // lock }
/// <summary>Begins tracking the specified background transactions</summary> /// <param name="transaction">Background transaction to be tracked</param> public void Track(Transaction transaction) { Track(transaction, 1.0f); }