Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

GoalBook - A Hybrid Smart Client

, 25 Sep 2009 CPOL
A WPF hybrid smart client that synchronises your goals with the Toodledo online To-do service.
GoalBook.zip
GoalBook
Dependencies
CAG WPF 2
Microsoft.Practices.Composite.dll
Microsoft.Practices.Composite.Presentation.dll
Microsoft.Practices.Composite.UnityExtensions.dll
Microsoft.Practices.ObjectBuilder2.dll
Microsoft.Practices.ServiceLocation.dll
Microsoft.Practices.Unity.dll
vssver2.scc
CSLA
Csla.dll
Csla.XmlSerializers.dll
vssver2.scc
Infragistics
Infragistics3.Wpf.DataPresenter.v9.1.Express.dll
Infragistics3.Wpf.Editors.v9.1.Express.dll
Infragistics3.Wpf.v9.1.Express.dll
vssver2.scc
WPFToolkit
vssver2.scc
WPFToolkit.dll
GoalBook.Controls
CheckedList
vssver2.scc
Properties
vssver2.scc
vssver2.scc
GoalBook.Goals
GoalBook.Goals.csproj.user
Properties
vssver2.scc
Views
vssver2.scc
vssver2.scc
GoalBook.Infrastructure
Comparers
vssver2.scc
Constants
vssver2.scc
Controls
Converters
vssver2.scc
Enums
vssver2.scc
Events
vssver2.scc
GoalBook.Infrastructure.csproj.user
Helpers
vssver2.scc
Interfaces
vssver2.scc
ObjectModel
vssver2.scc
Printing
vssver2.scc
Properties
vssver2.scc
vssver2.scc
GoalBook.Notes
GoalBook.Notes.csproj.user
Properties
vssver2.scc
Resources
arrow_redo.png
arrow_undo.png
cut.png
page_copy.png
paste_plain.png
text_bold.png
text_indent.png
text_indent_remove.png
text_italic.png
text_list_bullets.png
text_list_numbers.png
vssver2.scc
world_link.png
Views
vssver2.scc
vssver2.scc
GoalBook.Public
Encryption
vssver2.scc
HtmlConverter
vssver2.scc
HtmlParser
vssver2.scc
Misc
vssver2.scc
Properties
vssver2.scc
vssver2.scc
GoalBook.Shell
App.ico
Commands
vssver2.scc
GoalBook.Shell.csproj.user
Journal.ico
Journal48.ico
Misc
vssver2.scc
Modules
vssver2.scc
Properties
licenses.licx
vssver2.scc
Resources
arrow_refresh.png
arrow_undo.png
checked.gif
cross.png
disk.png
email.png
erase.png
error.png
exclamation.png
flag_red.png
group.png
help.png
information.png
magnifier.png
page_red.png
pencil.png
printer.png
user.png
vssver2.scc
Wave.jpg
world.png
world_link.png
Services
vssver2.scc
Splash.png
Views
vssver2.scc
vssver2.scc
Windows
vssver2.scc
GoalBook.snk
GoalBook.Synchronisation
Events
vssver2.scc
Properties
vssver2.scc
ToodleDo
vssver2.scc
vssver2.scc
GoalBook.Tasks
Controls
vssver2.scc
Properties
vssver2.scc
Views
vssver2.scc
vssver2.scc
vssver2.scc
// <copyright file="TasksViewPresenter.cs" company="GoalBook"> 
//    Copyright © 2009 Mark Brownsword. All rights reserved.
//    This source code and supporting files are licensed under The Code Project  
//    Open License (CPOL) as detailed at http://www.codeproject.com/info/cpol10.aspx. 
// </copyright>
namespace GoalBook.Tasks.Views
{
    #region Using Statements
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Windows;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using Csla;
    using GoalBook.Infrastructure;
    using GoalBook.Infrastructure.Constants;
    using GoalBook.Infrastructure.Converters;
    using GoalBook.Infrastructure.Enums;
    using GoalBook.Infrastructure.Events;
    using GoalBook.Infrastructure.Interfaces;
    using GoalBook.Infrastructure.ObjectModel;
    using Infragistics.Windows.DataPresenter;
    using Microsoft.Practices.Composite.Events;
    using Microsoft.Practices.Composite.Presentation.Commands;
    using Microsoft.Practices.Composite.Presentation.Events;
    #endregion

    /// <summary>
    /// TasksView Presenter. Interaction logic for TasksView.
    /// </summary>
    public class TasksViewPresenter
    {
        #region Constants and Enums
        /// <summary>
        /// Declaration for navigationService.
        /// </summary>
        private readonly INavigationService navigationService;

        /// <summary>
        /// Declaration for dialogService.
        /// </summary>
        private readonly IDialogService dialogService;

        /// <summary>
        /// Declaration for loggerService.
        /// </summary>
        private readonly ILoggerService loggerService;

        /// <summary>
        /// Declaration for persistenceService.
        /// </summary>
        private readonly IPersistenceService persistenceService;

        /// <summary>
        /// Declaration for eventAggregator.
        /// </summary>
        private readonly IEventAggregator eventAggregator;

        /// <summary>
        /// Declaration for printService.
        /// </summary>
        private readonly IPrintService printService;

        /// <summary>
        /// Declaration for settingsService.
        /// </summary>
        private readonly ISettingsService settingsService;
        #endregion

        #region Delegates and Events
        /// <summary>
        /// Declaration for newCommand.
        /// </summary>
        private DelegateCommand<CommandInfo> newCommand;

        /// <summary>
        /// Declaration for printCommand.
        /// </summary>
        private DelegateCommand<CommandInfo> printCommand;

        /// <summary>
        /// Declaration for undoCommand.
        /// </summary>
        private DelegateCommand<CommandInfo> undoCommand;

        /// <summary>
        /// Declaration for deleteCommand.
        /// </summary>
        private DelegateCommand<CommandInfo> deleteCommand;

        /// <summary>
        /// Declaration for searchCommand.
        /// </summary>
        private DelegateCommand<string> searchCommand;

        /// <summary>
        /// Declaration for clearCommand.
        /// </summary>
        private DelegateCommand<string> clearCommand;

        /// <summary>
        /// Declaration for XamlToFlowDocumentConverter.
        /// </summary>
        private XamlToFlowDocumentConverter xamlToFlowDocumentConverter;
        #endregion

        #region Instance and Shared Fields
        /// <summary>
        /// Declaration for syncInProgress.
        /// </summary>
        private bool syncInProgress = false;
        #endregion

        #region Constructors
        /// <summary>
        /// Initializes a new instance of the TasksViewPresenter class.
        /// </summary>
        /// <param name="navigationService">Reference to navigationService</param>
        /// <param name="dialogService">Reference to dialogService</param>
        /// <param name="loggerService">Reference to loggerService</param>
        /// <param name="persistenceService">Reference to persistenceService</param>
        /// <param name="eventAggregator">Reference to eventAggregator</param>
        /// <param name="printService">Reference to printService</param> 
        /// <param name="settingsService">Reference to settingsService</param>
        public TasksViewPresenter(
            INavigationService navigationService, 
            IDialogService dialogService, 
            ILoggerService loggerService,
            IPersistenceService persistenceService, 
            IEventAggregator eventAggregator,
            IPrintService printService, 
            ISettingsService settingsService)
        {
            // Set references.
            this.dialogService = dialogService;
            this.navigationService = navigationService;
            this.loggerService = loggerService;
            this.persistenceService = persistenceService;
            this.eventAggregator = eventAggregator;
            this.printService = printService;
            this.settingsService = settingsService;

            // Initialise Model.
            this.Model = new TasksViewPresentationModel();
            this.Model.Tasks = new FilteredBindingList<Task>(this.persistenceService.Tasks);
            this.Model.FolderList = new SortedBindingList<KeyValueItem>(this.persistenceService.Folders.FolderKeyValueItemList);
            this.Model.Tasks.ListChanged += this.Tasks_ListChanged;

            // Initialise the XamlToFlowDocumentConverter.
            this.xamlToFlowDocumentConverter = new XamlToFlowDocumentConverter();

            // Subscribe to events.
            this.persistenceService.Folders.ListChanged += this.Folders_ListChanged;
            this.persistenceService.SaveOccured += this.PersistenceService_SaveOccured;
            this.eventAggregator.GetEvent<SyncBeginEvent>().Subscribe(this.SyncBegin_EventHandler, ThreadOption.UIThread, true);
            this.eventAggregator.GetEvent<SyncEndEvent>().Subscribe(this.SyncEnd_EventHandler, ThreadOption.UIThread, true);

            // Initialise ReferenceData.            
            ReferenceData.FolderList = this.persistenceService.FetchFolderList();
            
            // Initialise Composite Commands. Note that these commands are active aware 
            // and will only execute when this view is the currently active view.
            this.printCommand = new DelegateCommand<CommandInfo>(this.PrintExecute_EventHandler, this.CanPrintExecute_EventHandler);
            this.undoCommand = new DelegateCommand<CommandInfo>(this.UndoExecute_EventHandler, this.CanUndoExecute_EventHandler);
            this.deleteCommand = new DelegateCommand<CommandInfo>(this.DeleteExecute_EventHandler, this.CanDeleteExecute_EventHandler);
            this.searchCommand = new DelegateCommand<string>(this.SearchExecute_EventHandler, this.CanSearchExecute_EventHandler);
            this.clearCommand = new DelegateCommand<string>(this.ClearExecute_EventHandler, this.CanClearExecute_EventHandler);

            // Register the commands.
            this.navigationService.RegisterInfoCommand(GlobalCommandType.Print, this.printCommand);
            this.navigationService.RegisterInfoCommand(GlobalCommandType.Undo, this.undoCommand);
            this.navigationService.RegisterInfoCommand(GlobalCommandType.Delete, this.deleteCommand);
            this.navigationService.RegisterStringCommand(GlobalCommandType.Search, this.searchCommand);
            this.navigationService.RegisterStringCommand(GlobalCommandType.Clear, this.clearCommand);
            //// NB: Remember to set new commands IsActive property in the View_IsActiveChanged event.
        }
        #endregion

        #region Properties
        /// <summary>
        /// Gets or sets Model.
        /// </summary>
        public TasksViewPresentationModel Model { get; set; }

        /// <summary>
        /// Gets or sets View.
        /// </summary>
        public TasksView View { get; set; }

        /// <summary>
        /// Gets or sets Reference to ActionView.
        /// </summary>
        public TasksActionView ActionView { get; set; }    

        /// <summary>
        /// Gets ViewMenuInfo. Called by Module 
        /// each time the this view is activated.
        /// </summary>
        public MenuInfo[] ViewMenuInfo
        {
            get { return this.GetMenuInfo(); }
        }
        #endregion

        #region Public and internal Methods
        /// <summary>
        /// Initialise the View.
        /// </summary>
        public void InitViews()
        {
            this.View.DataContext = this.Model;
            this.View.TaskSelected += new EventHandler(this.View_ItemSelected);
            this.View.IsActiveChanged += new EventHandler(this.View_IsActiveChanged);
            this.View.Activated += new EventHandler(this.View_Activated);
            this.View.EditActionInitiated += new EditActionEventHandler(this.View_EditActionInitiated);

            this.ActionView.DataContext = this.Model;
            this.ActionView.FolderFilter = null;            
            this.ActionView.FilterChanged += new EventHandler(this.ActionView_FilterChanged);
            
            this.Model.FolderList.ApplySort(KeyValueItem.OrderProperty.Name, ListSortDirection.Ascending);
            this.ApplyFilter();
        }

        /// <summary>
        /// Get New MenuInfo.
        /// </summary> 
        /// <returns>MenuInfo instance</returns>
        public MenuInfo GetNewMenuInfo()
        {
            MenuInfo menuInfo = new MenuInfo();

            this.newCommand = new DelegateCommand<CommandInfo>(this.NewExecute_EventHandler, this.CanNewExecute_EventHandler);
            menuInfo.MenuDelegateCommand = this.newCommand;
            menuInfo.MenuCommandInfo = new CommandInfo(
                Properties.Resources.NewTaskMenuText,
                0,
                ParentMenuType.New,
                new Uri(MenuConstants.MENU_NEW_TASK_IMAGE_URI),
                new KeyGesture(Key.T, ModifierKeys.Control | ModifierKeys.Shift, Properties.Resources.ModifierKeyControlShiftT));

            return menuInfo;
        }
        #endregion

        #region Base Class Overrides
        #endregion

        #region Private and Protected Methods
        /// <summary>
        /// Apply Title Filter.
        /// </summary>
        /// <param name="parameter">filter parameter</param>
        private void ApplyTitleFilter(string parameter)
        {
            this.Model.Tasks.FilterProvider = this.TitleFilter;
            this.Model.Tasks.ApplyFilter(Task.IdProperty.Name, parameter);
        }

        /// <summary>
        /// Title Filter.
        /// </summary>
        /// <param name="item">item parameter</param>
        /// <param name="filter">filter parameter</param>
        /// <returns>True if filter item found</returns>
        private bool TitleFilter(object item, object filter)
        {
            bool result = false;

            Guid id = new Guid(item.ToString());
            Task target = this.persistenceService.Tasks.Single(note => note.TaskID == id);

            if (target.Title.Contains(filter.ToString()) &&
                     this.TaskFilter(id, null))
            {
                result = true;
            }

            return result;
        }

        /// <summary>
        /// Apply Folder Filter.
        /// </summary>
        private void ApplyFilter()
        {
            this.Model.Tasks.FilterProvider = this.TaskFilter;
            this.Model.Tasks.ApplyFilter(Task.IdProperty.Name, null);                        
        }

        /// <summary>
        /// Task Filter.
        /// </summary>
        /// <param name="item">item parameter</param>
        /// <param name="filter">filter parameter</param>
        /// <returns>True if filter item found</returns>
        private bool TaskFilter(object item, object filter)
        {
            bool calendarResult = false;
            bool folderResult = false;

            Task target = this.persistenceService.Tasks.Single(task => task.TaskID == new Guid(item.ToString()));
                        
            switch (this.ActionView.CalendarFilter)
            {
                case TasksActionView.CalendarFilterOption.All:
                    calendarResult = true;
                    break;
                case TasksActionView.CalendarFilterOption.NoDate:
                    calendarResult = this.IsTaskNeverDue(target);
                    break;
                case TasksActionView.CalendarFilterOption.Past:
                    calendarResult = this.IsTaskDueInPast(target);
                    break;
                case TasksActionView.CalendarFilterOption.Today:
                    calendarResult = this.IsTaskDueToday(target);
                    break;
                case TasksActionView.CalendarFilterOption.ThisWeek:
                    calendarResult = this.IsTaskDueThisWeek(target);
                    break;
                case TasksActionView.CalendarFilterOption.Future:
                    calendarResult = this.IsTaskDueInFuture(target);
                    break;
                default:
                    break;
            }

            folderResult = this.ActionView.FolderFilter == null ? 
                        true : this.ActionView.FolderFilter.Contains(target.FolderID.ToString());

            return calendarResult && folderResult;      
        }

        /// <summary>
        /// Is Task Due In Future.
        /// </summary>
        /// <param name="target">Task parameter</param>
        /// <returns>True if specified task is due in the future</returns>
        private bool IsTaskDueInFuture(Task target)
        {
            return target.Due.HasValue ?
                        target.Due.Value > this.GetLastDayOfCurrentWeek() : false;
        }

        /// <summary>
        /// Is Task Due This Week.
        /// </summary>
        /// <param name="target">Task parameter</param>
        /// <returns>True if specified task is due this week</returns>
        private bool IsTaskDueThisWeek(Task target)
        {
            return target.Due.HasValue ?
                        target.Due.Value >= this.GetFirstDayOfCurrentWeek() &&
                        target.Due.Value <= this.GetLastDayOfCurrentWeek() : false;
        }

        /// <summary>
        /// Is Task Never Due.
        /// </summary>
        /// <param name="target">Task parameter</param>
        /// <returns>True if specified task has no due date</returns>
        private bool IsTaskNeverDue(Task target)
        {
            return target.Due.HasValue == false;
        }

        /// <summary>
        /// Is Task Due In Past.
        /// </summary>
        /// <param name="target">Task parameter</param>
        /// <returns>True if specified task is due in past</returns>
        private bool IsTaskDueInPast(Task target)
        {
            return target.Due < this.GetFirstDayOfCurrentWeek();
        }

        /// <summary>
        /// Is Task Due Today.
        /// </summary>
        /// <param name="target">Task parameter</param>
        /// <returns>True if specified task is due today</returns>
        private bool IsTaskDueToday(Task target)
        {
            return target.Due.HasValue ?
                        target.Due.Value.Year == DateTime.Now.Year &&
                        target.Due.Value.DayOfYear == DateTime.Now.DayOfYear : false;
        }

        /// <summary>
        /// Get FirstDayOfCurrentWeek.
        /// </summary>
        /// <returns>DateTime representing FirstDayOfCurrentWeek</returns>
        private DateTime GetFirstDayOfCurrentWeek()
        {
            DateTime result = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day);
            return result.AddDays(-(int)DateTime.Now.DayOfWeek);             
        }

        /// <summary>
        /// Get LastDayOfCurrentWeek.
        /// </summary>
        /// <returns>DateTime representing LastDayOfCurrentWeek</returns>
        private DateTime GetLastDayOfCurrentWeek()
        {
            DateTime result = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day).AddDays(1).AddSeconds(-1);
            
            switch (DateTime.Now.DayOfWeek)
            {
                default:
                    throw new ArgumentOutOfRangeException(string.Empty);
                case DayOfWeek.Sunday:
                    return result.AddDays(6);
                case DayOfWeek.Monday:
                    return result.AddDays(5);
                case DayOfWeek.Tuesday:
                    return result.AddDays(4);
                case DayOfWeek.Wednesday:
                    return result.AddDays(3);
                case DayOfWeek.Thursday:
                    return result.AddDays(2);
                case DayOfWeek.Friday:
                    return result.AddDays(1);
                case DayOfWeek.Saturday:
                    return result.AddDays(0);                
            }
        }
        
        /// <summary>
        /// GetMenuInfo. Returns all menuinfo instances for the module.
        /// </summary> 
        /// <returns>MenuInfo instances</returns>
        private MenuInfo[] GetMenuInfo()
        {
            List<MenuInfo> list = new List<MenuInfo>();
            ////list.Add(this.GetNewMenuInfo());

            return list.ToArray();
        }

        /// <summary>
        /// Initialise the DialogOptions.
        /// </summary>
        /// <param name="title">title for the dialog</param>
        /// <returns>DialogOptions instance</returns>
        private DialogOptions InitialiseDialogOptions(string title)
        {
            // Initialise DialogOptions.
            DialogOptions options = new DialogOptions();
            options.AllowResize = false;            
            options.DialogTitle = title;
            options.IconUri = new Uri(MenuConstants.MENU_NEW_TASK_IMAGE_URI);
            options.Buttons = ButtonType.OKCancel;

            return options;
        }

        /// <summary>
        /// Reset the List. Sorts item as required.
        /// </summary>
        private void ResetList()
        {
            // Refresh all list items.
            for (int i = 0; i < this.Model.Tasks.Count; i++)
            {
                this.persistenceService.Tasks.ResetItem(i);
            }
        }

        /// <summary>
        /// Perform DeleteAction.
        /// </summary>
        /// <param name="records">SelectedRecordCollection parameter</param>
        private void PerformDeleteAction(SelectedRecordCollection records)
        {
            Task task;
            foreach (DataRecord record in records)
            {
                task = record.DataItem as Task;

                // Initialise DialogOptions.
                DialogOptions options = new DialogOptions();
                options.AllowResize = false;
                options.DialogTitle = Properties.Resources.DeleteTaskText;
                options.DialogMessage = string.Format(Properties.Resources.DeleteTaskMessageText, task.Title);
                options.IconUri = new Uri(MenuConstants.MESSAGE_ERROR_IMAGE_URI);
                options.Buttons = ButtonType.YesNo;

                if (this.dialogService.ShowMessageDialog(options) == true)
                {
                    this.persistenceService.Tasks.BeginEdit();
                    this.Model.Tasks.Remove(task);
                }
            }
        }

        /// <summary>
        /// Perform Add Action.
        /// </summary>
        /// <param name="options">DialogOptions parameter</param>
        /// <param name="task">Task parameter</param>
        private void PerformAddAction(DialogOptions options, Task task)
        {            
            TasksDialogViewPresenter presenter = new TasksDialogViewPresenter(task, this.persistenceService, this.dialogService);

            presenter.View = new TasksDialogView();
            presenter.InitView();

            // Display the dialog.
            bool? result = this.dialogService.ShowView(
                presenter.View, 
                options,
                presenter.Model.EditTask as IDataErrorInfo);

            if (result == true)
            {
                if (task.IsSavable)
                {
                    Mouse.SetCursor(Cursors.Wait);
                    this.persistenceService.Tasks.BeginEdit();

                    // Add the pending item to the list.                
                    this.persistenceService.Tasks.Add(task);
                    this.persistenceService.Tasks.EndNew(this.Model.Tasks.IndexOf(task));

                    // Refresh Sort order.
                    this.View.SetItemActive(presenter.Model.EditTask);
                    this.View.RefreshSortPosition(true);
                }                
            }
        }

        /// <summary>
        /// Perform Edit Action.
        /// </summary>
        /// <param name="options">DialogOptions parameter</param>
        /// <param name="task">Task parameter</param>
        private void PerformEditAction(DialogOptions options, Task task)
        {
            TasksDialogViewPresenter presenter = new TasksDialogViewPresenter(task, this.persistenceService, this.dialogService);

            presenter.View = new TasksDialogView();
            presenter.InitView();

            // Display the dialog.
            bool? result = this.dialogService.ShowView(
                presenter.View,
                options,
                presenter.Model.EditTask as IDataErrorInfo);

            if (result == true)
            {
                if (task.IsSavable)
                {
                    Mouse.SetCursor(Cursors.Wait);

                    // Locate the task in the list.
                    for (int i = 0; i < this.Model.Tasks.Count; i++)
                    {
                        if (this.Model.Tasks[i].TaskID == task.TaskID)
                        {
                            this.persistenceService.Tasks.BeginEdit();

                            // Apply the changes.
                            this.Model.Tasks[i].MapFields(task);
                            
                            // Refresh the ActiveRecord.
                            this.View.RefreshSortPosition(true);

                            break;
                        }
                    }
                }                
            }
        }

        /// <summary>
        /// Initialise Edit Action.
        /// </summary>
        /// <param name="e">EditActionEventArgs parameter</param>
        private void InitialiseEditAction(EditActionEventArgs e)
        {
            SelectedRecordCollection records = e.Records;
            if (records.Count > 0 && records[records.Count - 1] is DataRecord)
            {
                // Edit the last item in the collection. That is the one with the row selector applied.
                DataRecord record = records[records.Count - 1] as DataRecord;

                if (record.DataItem is Task)
                {
                    this.PerformEditAction(this.InitialiseDialogOptions(Properties.Resources.EditTask), (record.DataItem as Task).Clone());                    
                }
            }
        }

        /// <summary>
        /// Raise NewCanExecuteChanged.
        /// </summary>
        private void RaiseNewCanExecuteChanged()
        {
            this.newCommand.RaiseCanExecuteChanged();
        }

        /// <summary>
        /// Raise PrintCanExecuteChanged.
        /// </summary>
        private void RaisePrintCanExecuteChanged()
        {
            this.printCommand.RaiseCanExecuteChanged();
        }

        /// <summary>
        /// Raise UndoCanExecuteChanged.
        /// </summary>
        private void RaiseUndoCanExecuteChanged()
        {
            this.undoCommand.RaiseCanExecuteChanged();
        }

        /// <summary>
        /// Raise DeleteCanExecuteChanged.
        /// </summary>
        private void RaiseDeleteCanExecuteChanged()
        {
            this.deleteCommand.RaiseCanExecuteChanged();
        }

        /// <summary>
        /// Raise SearchCanExecuteChanged.
        /// </summary>
        private void RaiseSearchCanExecuteChanged()
        {
            this.searchCommand.RaiseCanExecuteChanged();
        }

        /// <summary>
        /// Raise ClearCanExecuteChanged.
        /// </summary>
        private void RaiseClearCanExecuteChanged()
        {
            this.clearCommand.RaiseCanExecuteChanged();
        }

        /// <summary>
        /// Notify Command SyncInProgress. Ensure menuitems for editing
        /// goals are disabled during synchronisation.
        /// </summary>
        /// <param name="syncInProgress">Flag indicating if sync is running</param>
        private void NotifyCommandSyncInProgress(bool syncInProgress)
        {
            this.syncInProgress = syncInProgress;

            this.RaiseNewCanExecuteChanged();
            this.RaisePrintCanExecuteChanged();
            this.RaiseUndoCanExecuteChanged();
            this.RaiseDeleteCanExecuteChanged();
            this.RaiseSearchCanExecuteChanged();
            this.RaiseClearCanExecuteChanged();            
        }

        /// <summary>
        /// Select Active Record.
        /// </summary>
        private void SelectActiveRecord()
        {
            if (this.View.xamDataGridTasks.ActiveRecord != null)
            {
                this.View.xamDataGridTasks.Focus();
                this.View.xamDataGridTasks.ActiveRecord.IsSelected = true;
            }
        }

        /// <summary>
        /// Get Cloned Task.
        /// </summary>
        /// <param name="taskID">taskID parameter</param>
        /// <returns>Task matching the specified identifier or null</returns>
        private Task GetClonedNote(Guid taskID)
        {
            foreach (Task task in this.Model.Tasks)
            {
                if (task.TaskID == taskID)
                {
                    return task.Clone();
                }
            }

            return null;
        }
        
        /// <summary>
        /// Get Print TableRow.
        /// </summary>
        /// <param name="title">title parameter</param>
        /// <param name="value">value parameter</param>
        /// <returns>TableRow instance</returns>
        private TableRow GetPrintTableRow(string title, string value)
        {
            TableRow row = new TableRow();
            row.FontFamily = new FontFamily(PrintConstants.FONT_FAMILY_ARIAL);
            row.FontSize = 12;
            row.FontWeight = FontWeights.Normal;

            // Title cell
            TableCell titleCell = new TableCell(new Paragraph(new Run(title)));
            titleCell.FontWeight = FontWeights.Bold;
            row.Cells.Add(titleCell);

            // Value cell
            row.Cells.Add(new TableCell(new Paragraph(new Run(value))));

            return row;
        }

        /// <summary>
        /// Show Status Count Message.
        /// </summary>
        private void ShowStatusCountMessage()
        {
            if (this.View.IsActive)
            {
                this.navigationService.ShowStatusMessage(string.Format(
                    Properties.Resources.StatusCountMessage,
                    this.Model.Tasks.Count,
                    this.Model.Tasks.Count == 1 ? string.Empty : Properties.Resources.StatusCountPluralCharacter,
                    this.persistenceService.Tasks.Count));
            }
        }
        #endregion

        #region Event Handlers
        /// <summary>
        /// Handle ActionView_FilterChanged event.
        /// </summary>
        /// <param name="sender">sender parameter</param>
        /// <param name="e">EventArgs parameter</param>
        private void ActionView_FilterChanged(object sender, EventArgs e)
        {
            if (this.syncInProgress)
            {
                return;
            }

            this.ApplyFilter();            
        }

        /// <summary>
        /// Handle View_ItemSelected event.
        /// </summary>
        /// <param name="sender">sender parameter</param>
        /// <param name="e">EventArgs parameter</param>        
        private void View_ItemSelected(object sender, EventArgs e)
        {
            this.RaisePrintCanExecuteChanged();
            this.RaiseDeleteCanExecuteChanged();            
        }

        /// <summary>
        /// Handle View_Activated event.
        /// </summary>
        /// <param name="sender">sender parameter</param>
        /// <param name="e">EventArgs parameter</param>       
        private void View_Activated(object sender, EventArgs e)
        {
            this.SelectActiveRecord();            
        }

        /// <summary>
        /// Handle View_EditActionInitiated event.
        /// </summary>
        /// <param name="e">EditActionEventArgs parameter</param>       
        private void View_EditActionInitiated(EditActionEventArgs e)
        {
            if (this.syncInProgress)
            {
                return;
            }

            switch (e.EditAction)
            {
                case EditActionType.Cut:
                    break;
                case EditActionType.Copy:
                    break;
                case EditActionType.Paste:
                    break;
                case EditActionType.Delete:
                    break;
                case EditActionType.Edit:
                    this.InitialiseEditAction(e);
                    this.ApplyFilter(); 
                    break;
            }
        }
        
        /// <summary>
        /// Handle Tasks_ListChanged event.
        /// </summary>
        /// <param name="sender">Source of caller</param>
        /// <param name="e">ListChangedEventArgs parameter</param>
        private void Tasks_ListChanged(object sender, ListChangedEventArgs e)
        {
            this.RaisePrintCanExecuteChanged();
            this.RaiseUndoCanExecuteChanged();
            this.RaiseDeleteCanExecuteChanged();
            this.RaiseSearchCanExecuteChanged();
            this.RaiseClearCanExecuteChanged();

            this.ShowStatusCountMessage();
        }

        /// <summary>
        /// Handle Folders_ListChanged event.
        /// </summary>
        /// <param name="sender">sender parameter</param>
        /// <param name="e">ListChangedEventArgs parameter</param>
        private void Folders_ListChanged(object sender, ListChangedEventArgs e)
        {
            switch (e.ListChangedType)
            {
                case ListChangedType.ItemAdded:
                    if (this.ActionView.FolderFilter != null)
                    {
                        // Add new items to the FolderFilter, so they appear checked by default.
                        this.ActionView.FolderFilter += string.Concat(
                            this.ActionView.FolderFilter.Length > 0 ? "," : string.Empty,
                            this.persistenceService.Folders[e.NewIndex].FolderID.ToString());
                    }

                    break;
                case ListChangedType.Reset:
                    this.ApplyFilter();                    
                    break;
            }
        }

        /// <summary>
        /// Handle PersistenceService_SaveOccured event.
        /// </summary>
        /// <param name="sender">Source of caller</param>
        /// <param name="e">EventArgs parameter</param>
        private void PersistenceService_SaveOccured(object sender, EventArgs e)
        {
            this.RaiseUndoCanExecuteChanged();
        }

        /// <summary>
        /// Handle SyncBegin_EventHandler event.
        /// </summary>
        /// <param name="payload">payload parameter</param>
        private void SyncBegin_EventHandler(string payload)
        {            
            this.NotifyCommandSyncInProgress(true);
            this.ActionView.IsEnabled = this.ActionView.ListenForListChangedEvents = false;
        }

        /// <summary>
        /// Handle SyncEnd_EventHandler event.
        /// </summary>
        /// <param name="payload">payload parameter</param>
        private void SyncEnd_EventHandler(string payload)
        {
            this.ResetList();

            if (this.View.IsActive)
            {
                this.View.Activate();
            }

            this.View.RefreshSortPosition(false);
            this.NotifyCommandSyncInProgress(false);

            this.ActionView.IsEnabled = this.ActionView.ListenForListChangedEvents = true;
            
            this.Model.FolderList.ApplySort(KeyValueItem.OrderProperty.Name, ListSortDirection.Ascending);
            this.ApplyFilter();
        }

        /// <summary>
        /// Handle View_IsActiveChanged event.
        /// </summary>
        /// <param name="sender">Source of caller</param>
        /// <param name="e">EventArgs parameter</param>
        private void View_IsActiveChanged(object sender, EventArgs e)
        {
            this.printCommand.IsActive =
            this.undoCommand.IsActive =
            this.deleteCommand.IsActive =
            this.searchCommand.IsActive =
            this.clearCommand.IsActive = this.View.IsActive;

            this.ShowStatusCountMessage();
        }

        /// <summary>
        /// Handle PrintExecute_EventHandler event.
        /// </summary>
        /// <param name="parameter">CommandInfo parameter</param>      
        private void PrintExecute_EventHandler(CommandInfo parameter)
        {
            foreach (DataRecord record in this.View.SelectedTasks)
            {
                if (record.DataItem is Task)
                {
                    Task task = record.DataItem as Task;

                    // Initialise the FlowDocument.
                    FlowDocument document = new FlowDocument();

                    // Initialise Table.
                    Table table = new Table();
                    table.CellSpacing = 15;
                    table.Background = Brushes.White;
                    table.Columns.Add(new TableColumn());
                    table.Columns[0].Width = new GridLength(75, GridUnitType.Pixel);
                    table.RowGroups.Add(new TableRowGroup());
                    
                    // Initialise Rows.
                    TableRowGroup rowGroup = table.RowGroups[0];
                    rowGroup.Rows.Add(this.GetPrintTableRow(Properties.Resources.LabelTitle, task.Title));
                    rowGroup.Rows.Add(this.GetPrintTableRow(Properties.Resources.LabelFolder, this.persistenceService.FetchFolderList()[task.FolderID].ToString()));
                    rowGroup.Rows.Add(this.GetPrintTableRow(Properties.Resources.LabelDueDate, task.Due.HasValue ? task.Due.Value.ToShortDateString() : null));
                    rowGroup.Rows.Add(this.GetPrintTableRow(Properties.Resources.LabelDueTime, task.DueTime.HasValue ? task.DueTime.ToString() : null));
                    
                    // Add the table to the FlowDocument.
                    document.Blocks.Add(table);

                    // Pass the FlowDocument to PrintService.
                    this.printService.Print(Properties.Resources.LabelTask, document);
                }
            }
        }

        /// <summary>
        /// Handle CanPrintExecute_EventHandler event.
        /// </summary>
        /// <param name="parameter">CommandInfo parameter</param>
        /// <returns>True if can print</returns>
        private bool CanPrintExecute_EventHandler(CommandInfo parameter)
        {
            return this.View.SelectedTasksCount > 0 && !this.syncInProgress;
        }

        /// <summary>
        /// Handle UndoExecute_EventHandler event.
        /// </summary>  
        /// <param name="parameter">CommandInfo parameter</param>
        private void UndoExecute_EventHandler(CommandInfo parameter)
        {
            // Roll the EditLevel back by one.
            this.persistenceService.Tasks.CancelEdit();

            this.ResetList();
            this.SelectActiveRecord();
        }

        /// <summary>
        /// Handle CanUndoExecute_EventHandler event.
        /// </summary> 
        /// <param name="parameter">CommandInfo parameter</param>
        /// <returns>True if command can execute</returns>
        private bool CanUndoExecute_EventHandler(CommandInfo parameter)
        {
            return this.persistenceService.Tasks.EditLevel > 0 && !this.syncInProgress;
        }

        /// <summary>
        /// Handle DeleteExecute_EventHandler event.
        /// </summary>        
        /// <param name="parameter">CommandInfo parameter</param>
        private void DeleteExecute_EventHandler(CommandInfo parameter)
        {
            this.PerformDeleteAction(this.View.SelectedTasks);

            this.ResetList();
            this.SelectActiveRecord();
        }

        /// <summary>
        /// Handle CanDeleteExecute_EventHandler event.
        /// </summary>        
        /// <param name="parameter">CommandInfo parameter</param>
        /// <returns>True if command can execute</returns>
        private bool CanDeleteExecute_EventHandler(CommandInfo parameter)
        {
            return this.View.SelectedTasksCount > 0 && !this.syncInProgress;
        }

        /// <summary>
        /// Handle SearchExecute_EventHandler event.
        /// </summary> 
        /// <param name="parameter">string parameter</param>        
        private void SearchExecute_EventHandler(string parameter)
        {
            this.ApplyTitleFilter(parameter);
        }

        /// <summary>
        /// Handle CanSearchExecute_EventHandler event.
        /// </summary>
        /// <param name="parameter">string parameter</param>
        /// <returns>True if command can execute</returns>
        private bool CanSearchExecute_EventHandler(string parameter)
        {
            return !this.syncInProgress;
        }

        /// <summary>
        /// Handle ClearExecute_EventHandler event.
        /// </summary>
        /// <param name="parameter">string parameter</param>
        private void ClearExecute_EventHandler(string parameter)
        {
            this.ApplyFilter();
        }

        /// <summary>
        /// Handle CanClearExecute_EventHandler event.
        /// </summary>
        /// <param name="parameter">string parameter</param>
        /// <returns>True if command can execute</returns>
        private bool CanClearExecute_EventHandler(string parameter)
        {
            return !this.syncInProgress;
        }

        /// <summary>
        /// Handle NewExecute_EventHandler event.
        /// </summary>
        /// <param name="parameter">CommandInfo parameter</param>
        private void NewExecute_EventHandler(CommandInfo parameter)
        {
            Task task = new Task(Guid.NewGuid());
            
            this.PerformAddAction(this.InitialiseDialogOptions(Properties.Resources.NewTaskDialogText), task);
            this.ApplyFilter(); 
        }

        /// <summary>
        /// Handle CanNewExecute_EventHandler event.
        /// </summary>        
        /// <param name="parameter">CommandInfo parameter</param>
        /// <returns>True if command can execute</returns>
        private bool CanNewExecute_EventHandler(CommandInfo parameter)
        {
            return !this.syncInProgress;
        }
        #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)

Share

About the Author

Mark Brownsword
Software Developer (Senior)
Australia Australia
I've been working as a software developer since 2000 and hold a Bachelor of Business degree from The Open Polytechnic of New Zealand. Computers are for people and I aim to build applications for people that they would want to use.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.1411023.1 | Last Updated 25 Sep 2009
Article Copyright 2009 by Mark Brownsword
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid