Click here to Skip to main content
15,879,535 members
Articles / Desktop Programming / WPF

Create MVVM Background Tasks with Progress Reporting

Rate me:
Please Sign up or sign in to vote.
4.93/5 (34 votes)
9 Sep 2011CPOL18 min read 93.2K   6.1K   85  
This article explains how to implement background processing and parallel processing for time consuming tasks in MVVM, and how to create a progress dialog with cancellation for those tasks.
#region Copyright Notice

// Distributed under the Code Project Open License 
// ****************************************************
// 
// Copyright � 2011. David C. Veeneman
// All rights reserved 
// 
// Redistribution and use on source and binary forms, with or without modification 
// are permitted provided that the following conditions are met:
// 
// � Redistributions of source code must retain the above copyright notice, this 
// list of conditions and the following disclaimers. 
// 
// � Redistributions on binary form must reproduce the above copyright notice, this 
// list of conditions and the following disclaimer in the documentation anclior other 
// materials provided with the distribution. 
// 
// � Neither the name of David C. Veeneman nor Foresight Systems may be used to endorse 
// or promote products derived from this software without specific prior written permission. 
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES, 
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID C VEENEMAN OR FORERSIGHT SYSTEMS BE 
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSITTUIE GOODS OR SERVICES: LOSS OF USE, DATA OR PROFITS; OR 
// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
// LIABILITY, OR TORT. 

#endregion

using System;
using System.Threading;
using System.Windows.Input;
using WpfProgressDemo.Operations.Commands;

namespace WpfProgressDemo.ViewModel
{
    public class ProgressDialogViewModel : ViewModelBase
    {
        #region Fields

        // Property variables
        private int p_Progress;
        private string p_ProgressMessage;
        private int p_ProgressMax;

        //Member variables
        private MainWindowViewModel m_Parent;
        private string m_ProgressMessageTemplate;
        private string m_CancellationMessage;

        #endregion

        #region Constructor

        public ProgressDialogViewModel(MainWindowViewModel mainWindowViewModel)
        {
            Initialize(mainWindowViewModel);
        }

        #endregion

        #region Admin Properties

        /// <summary>
        /// A cancellation token source for the background operations.
        /// </summary>
        internal CancellationTokenSource TokenSource { get; set; }

        /// <summary>
        /// Whether the operation in progress has been cancelled.
        /// </summary>
        /// <remarks> 
        /// The Cancel command is invoked by the Cancel button, and on the window
        /// close (in case the user clicks the close box to cancel. The Cancel 
        /// command sets this property and checks it to make sure that the command 
        /// isn't run twice when the user clicks the Cancel button (once for the 
        /// button-click, and once for the window-close.
        /// </remarks>
        public bool IsCancelled { get; set; }
        #endregion

        #region Command Properties

        /// <summary>
        /// The Cancel command.
        /// </summary>
        public ICommand Cancel { get; set; }

        #endregion

        #region Data Properties

        /// <summary>
        /// The progress of an image processing job.
        /// </summary>
        /// <remarks>
        /// The setter for this property also sets the ProgressMessage property.
        /// </remarks>
        public int Progress
        {
            get { return p_Progress; }

            set
            {
                base.RaisePropertyChangingEvent("Progress");
                p_Progress = value;
                base.RaisePropertyChangedEvent("Progress");
            }
        }

        /// <summary>
        /// The maximum progress value.
        /// </summary>
        /// <remarks>
        /// The 
        /// </remarks>
        public int ProgressMax
        {
            get { return p_ProgressMax; }

            set
            {
                base.RaisePropertyChangingEvent("ProgressMax");
                p_ProgressMax = value;
                base.RaisePropertyChangedEvent("ProgressMax");
            }
        }

        /// <summary>
        /// The status message to be displayed in the View.
        /// </summary>
        public string ProgressMessage
        {
            get { return p_ProgressMessage; }

            set
            {
                base.RaisePropertyChangingEvent("ProgressMessage");
                p_ProgressMessage = value;
                base.RaisePropertyChangedEvent("ProgressMessage");
            }
        }

        #endregion

        #region Internal Methods

        /// <summary>
        /// Clears the view model.
        /// </summary>
        internal void ClearViewModel()
        {
            p_Progress = 0;
            p_ProgressMax = 0;
            p_ProgressMessage = "Preparing to perform simulated work.";
            this.IsCancelled = false;
        }

        /// <summary>
        /// Advances the progress counter for the Progress dialog.
        /// </summary>
        /// <param name="incrementClicks">The number of 'clicks' to advance the counter.</param>
        internal void IncrementProgressCounter(int incrementClicks)
        {
            // Increment counter
            this.Progress += incrementClicks;

            // Update progress message
            var progress = Convert.ToSingle(p_Progress);
            var progressMax = Convert.ToSingle(p_ProgressMax);
            var f = (progress/progressMax)*100;
            var percentComplete = Single.IsNaN(f) ? 0 : Convert.ToInt32(f);
            this.ProgressMessage = string.Format(m_ProgressMessageTemplate, percentComplete);
        }

        /// <summary>
        /// Sets the progreess message to show that processing was cancelled.
        /// </summary>
        internal void ShowCancellationMessage()
        {
            this.ProgressMessage = m_CancellationMessage;
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Initializes this view model.
        /// </summary>
        /// <param name="mainWindowViewModel">The view model for this application's main window.</param>
        private void Initialize(MainWindowViewModel mainWindowViewModel)
        {
            m_Parent = mainWindowViewModel;
            m_ProgressMessageTemplate = "Simulated work {0}% complete";
            m_CancellationMessage = "Simulated work cancelled";
            this.Cancel = new CancelCommand(this);
            this.ClearViewModel();
        }

        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Foresight Systems
United States United States
David Veeneman is a financial planner and software developer. He is the author of "The Fortune in Your Future" (McGraw-Hill 1998). His company, Foresight Systems, develops planning and financial software.

Comments and Discussions