Click here to Skip to main content
15,867,762 members
Articles / Desktop Programming / WPF

Building WPF Applications with Self-Tracking Entity Generator - Project Setup

Rate me:
Please Sign up or sign in to vote.
4.80/5 (11 votes)
20 Feb 2012CPOL10 min read 75K   4.8K   54  
This article describes the project setup of building a WPF sample application with Self-Tracking Entity Generator for WPF/Silverlight.
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.Linq;
using System.Windows;
using System.Windows.Data;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using SchoolSample.Common;
using SchoolSample.EntityModel;

namespace SchoolSample.ViewModel
{
    [Export(ViewModelTypes.CoursePageViewModel, typeof(ViewModelBase))]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class CoursePageViewModel : ViewModelBase
    {
        #region "Private Data Members"
        private ISchoolModel _schoolModel;
        #endregion "Private Data Members"

        #region "Constructor"
        [ImportingConstructor]
        public CoursePageViewModel(ISchoolModel schoolModel)
        {
            _schoolModel = schoolModel;

            // set up event handling
            _schoolModel.PropertyChanged += _schoolModel_PropertyChanged;
            _schoolModel.GetStudentsCompleted += _schoolModel_GetStudentsCompleted;
            _schoolModel.GetInstructorsCompleted += _schoolModel_GetInstructorsCompleted;
            _schoolModel.GetCoursesCompleted += _schoolModel_GetCoursesCompleted;
            _schoolModel.GetCourseByIdCompleted += _schoolModel_GetCourseByIdCompleted;
            _schoolModel.SaveCourseChangesCompleted += _schoolModel_SaveCourseChangesCompleted;

            PropertyChanged += CoursePageViewModel_PropertyChanged;

            // get students
            _schoolModel.GetStudentsAsync("None", "CoursePage");
            // get instructors
            _schoolModel.GetInstructorsAsync("None", "CoursePage");
            // get courses
            _schoolModel.GetCoursesAsync("CoursePage");

            // set up initial screen status
            CourseFormEndEdit();
            EnrollmentFormEndEdit();
        }
        #endregion "Constructor"

        #region "Public Properties"

        /// <summary>
        /// All courses collection returns/updates CoursesList from _schoolModel,
        /// _allCoursesCache keeps a local reference to the list and it syncs with
        /// _schoolModel.CoursesList when navigates to this page 
        /// </summary>
        private ObservableCollection<Course> AllCourses
        {
            get
            {
                return _schoolModel != null ? _schoolModel.CoursesList : null;
            }
            set
            {
                if (!ReferenceEquals(_allCoursesCache, value))
                {
                    _allCoursesCache = value;
                    // update CoursesList on the model
                    if (_schoolModel != null) _schoolModel.CoursesList = _allCoursesCache;
                }
            }
        }

        private ObservableCollection<Course> _allCoursesCache;

        public CollectionViewSource AllCoursesSource
        {
            get { return _allCoursesSource; }
            private set
            {
                if (!ReferenceEquals(_allCoursesSource, value))
                {
                    _allCoursesSource = value;
                    RaisePropertyChanged("AllCoursesSource");
                }
            }
        }

        private CollectionViewSource _allCoursesSource;

        /// <summary>
        /// CurrentCourse returns/updates CurrentCourse from _schoolModel,
        /// _currentCourseCache keeps a local reference to the object and it
        /// syncs with _schoolModel.CurrentCourse when navigates to this page 
        /// </summary>
        public Course CurrentCourse
        {
            get
            {
                return _schoolModel != null ? _schoolModel.CurrentCourse : null;
            }
            private set
            {
                if (!ReferenceEquals(_currentCourseCache, value))
                {
                    _currentCourseCache = value;
                    if (_schoolModel != null) _schoolModel.CurrentCourse = _currentCourseCache;
                    RaisePropertyChanged("CurrentCourse");
                }
            }
        }

        private Course _currentCourseCache;

        public CollectionViewSource EnrollmentsSource
        {
            get { return _enrollmentsSource; }
            private set
            {
                if (!ReferenceEquals(_enrollmentsSource, value))
                {
                    _enrollmentsSource = value;
                    RaisePropertyChanged("EnrollmentsSource");
                }
            }
        }

        private CollectionViewSource _enrollmentsSource;

        public Enrollment CurrentEnrollment
        {
            get { return _currentEnrollment; }
            private set
            {
                if (!ReferenceEquals(_currentEnrollment, value))
                {
                    _currentEnrollment = value;
                    RaisePropertyChanged("CurrentEnrollment");
                }
            }
        }

        private Enrollment _currentEnrollment;

        private ObservableCollection<Student> _allStudents;

        public CollectionViewSource AllStudentsSource
        {
            get { return _allStudentsSource; }
            private set
            {
                if (!ReferenceEquals(_allStudentsSource, value))
                {
                    _allStudentsSource = value;
                    RaisePropertyChanged("AllStudentsSource");
                }
            }
        }

        private CollectionViewSource _allStudentsSource;

        private ObservableCollection<Instructor> _allInstructors;

        public CollectionViewSource AllInstructorsSource
        {
            get { return _allInstructorsSource; }
            private set
            {
                if (!ReferenceEquals(_allInstructorsSource, value))
                {
                    _allInstructorsSource = value;
                    RaisePropertyChanged("AllInstructorsSource");
                }
            }
        }

        private CollectionViewSource _allInstructorsSource;

        public bool CourseFormInEdit
        {
            get { return _courseFormInEdit; }
            private set
            {
                if (_courseFormInEdit != value)
                {
                    _courseFormInEdit = value;
                    RaisePropertyChanged("CourseFormInEdit");
                }
            }
        }

        private bool _courseFormInEdit;

        public bool CurrentCourseHasErrors
        {
            get { return _currentCourseHasErrors; }
            set
            {
                if (_currentCourseHasErrors != value)
                {
                    _currentCourseHasErrors = value;
                    RaisePropertyChanged("CurrentCourseHasErrors");
                }
            }
        }

        private bool _currentCourseHasErrors;

        public bool EnrollmentFormInEdit
        {
            get { return _enrollmentFormInEdit; }
            private set
            {
                if (_enrollmentFormInEdit != value)
                {
                    _enrollmentFormInEdit = value;
                    RaisePropertyChanged("EnrollmentFormInEdit");
                }
            }
        }

        private bool _enrollmentFormInEdit;

        public bool CurrentEnrollmentHasErrors
        {
            get { return _currentEnrollmentHasErrors; }
            set
            {
                if (_currentEnrollmentHasErrors != value)
                {
                    _currentEnrollmentHasErrors = value;
                    RaisePropertyChanged("CurrentEnrollmentHasErrors");
                }
            }
        }

        private bool _currentEnrollmentHasErrors;

        public bool CourseListIsEnabled
        {
            get { return _courseListIsEnabled; }
            private set
            {
                if (_courseListIsEnabled != value)
                {
                    _courseListIsEnabled = value;
                    RaisePropertyChanged("CourseListIsEnabled");
                }
            }
        }

        private bool _courseListIsEnabled = true;

        public bool EnrollmentListIsEnabled
        {
            get { return _enrollmentListIsEnabled; }
            private set
            {
                if (_enrollmentListIsEnabled != value)
                {
                    _enrollmentListIsEnabled = value;
                    RaisePropertyChanged("EnrollmentListIsEnabled");
                }
            }
        }

        private bool _enrollmentListIsEnabled = true;

        public bool StudentComboIsEditable
        {
            get { return _studentComboIsEditable; }
            private set
            {
                if (_studentComboIsEditable != value)
                {
                    _studentComboIsEditable = value;
                    RaisePropertyChanged("StudentComboIsEditable");
                }
            }
        }

        private bool _studentComboIsEditable;

        #endregion "Public Properties"

        #region "Public Commands"

        /// <summary>
        /// Command for Page Loaded event
        /// </summary>
        public RelayCommand PageLoadedCommand
        {
            get
            {
                if (_pageLoadedCommand == null)
                {
                    _pageLoadedCommand = new RelayCommand(
                        OnPageLoadedCommand);
                }
                return _pageLoadedCommand;
            }
        }

        private RelayCommand _pageLoadedCommand;

        private void OnPageLoadedCommand()
        {
            // synchronize _schoolModel.CoursesList with local cache
            if (_schoolModel != null && _allCoursesCache != null)
                _schoolModel.CoursesList = _allCoursesCache;
            // synchronize _schoolModel.CurrentCourse with local cache
            if (_schoolModel != null && _currentCourseCache != null)
                _schoolModel.CurrentCourse = _currentCourseCache;
        }

        /// <summary>
        /// Command for Page Unloaded event
        /// </summary>
        public RelayCommand PageUnLoadedCommand
        {
            get
            {
                if (_pageUnLoadedCommand == null)
                {
                    _pageUnLoadedCommand = new RelayCommand(
                        OnPageUnLoadedCommand);
                }
                return _pageUnLoadedCommand;
            }
        }

        private RelayCommand _pageUnLoadedCommand;

        private void OnPageUnLoadedCommand()
        {
            // clean up
            if (_schoolModel != null)
            {
                _schoolModel.CoursesList = null;
                _schoolModel.CurrentCourse = null;
            }
        }

        /// <summary>
        /// Add course command. We can add a new course
        /// when neither course nor enrollment form is in edit
        /// </summary>
        public RelayCommand AddCourseCommand
        {
            get
            {
                if (_addCourseCommand == null)
                {
                    _addCourseCommand = new RelayCommand(
                        OnAddCourseCommand,
                        () => !CourseFormInEdit && !EnrollmentFormInEdit);
                }
                return _addCourseCommand;
            }
        }

        private RelayCommand _addCourseCommand;

        private void OnAddCourseCommand()
        {
            // create a temporary courseId
            int newCourseId = AllCourses.Count > 0
                                  ? ((from course in AllCourses select Math.Abs(course.CourseId)).Max() + 1)*(-1)
                                  : -1;
            // create a new course
            CurrentCourse = new Course
                                {
                                    SuspendValidation = true,
                                    CourseId = newCourseId,
                                    Title = string.Empty
                                };
            CurrentCourse.SuspendValidation = false;
            // no current enrollment yet
            EnrollmentsSource = new CollectionViewSource {Source = CurrentCourse.Enrollments};
            EnrollmentsSource.SortDescriptions.Add(new SortDescription("EnrollmentId", ListSortDirection.Ascending));
            EnrollmentsSource.View.CurrentChanged += EnrollmentsSourceView_CurrentChanged;
            CurrentEnrollment = null;
            // and begin edit
            OnEditCommitCourseCommand();
        }

        /// <summary>
        /// Delete course command. We can delete an course
        /// when the current course is not null, and neither course
        /// nor enrollment form is in edit
        /// </summary>
        public RelayCommand DeleteCourseCommand
        {
            get
            {
                if (_deleteCourseCommand == null)
                {
                    _deleteCourseCommand = new RelayCommand(
                        OnDeleteCourseCommand,
                        () => (CurrentCourse != null) && !CourseFormInEdit && !EnrollmentFormInEdit);
                }
                return _deleteCourseCommand;
            }
        }

        private RelayCommand _deleteCourseCommand;

        private void OnDeleteCourseCommand()
        {
            try
            {
                if (CurrentCourse != null)
                {
                    // ask to confirm deleting the current course
                    DialogMessage dialogMessage = new DialogMessage(
                        this,
                        ApplicationStrings.DeleteCurrentCourseMessageBoxText,
                        s =>
                        {
                            if (s == MessageBoxResult.OK)
                            {
                                if (CurrentCourse.ChangeTracker.State == ObjectState.Added)
                                {
                                    // if State is Added, simply remove from the CoursesList
                                    // as the database does not have this record yet
                                    CurrentCourse.MarkAsDeleted();
                                    AllCourses.Remove(CurrentCourse);
                                }
                                else
                                {
                                    // if confirmed, remove current course
                                    CurrentCourse.MarkAsDeleted();
                                    _schoolModel.SaveCourseChangesAsync(false);
                                }
                            }
                        })
                    {
                        Button = MessageBoxButton.OKCancel,
                        Caption = ApplicationStrings.ConfirmMessageBoxCaption
                    };
                    AppMessages.PleaseConfirmMessage.Send(dialogMessage);
                }
            }
            catch (Exception ex)
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(ex);
            }
        }

        /// <summary>
        /// Edit/Commit an course. We can edit/commit an course
        /// when current course is not null
        /// </summary>
        public RelayCommand EditCommitCourseCommand
        {
            get
            {
                if (_editCommitCourseCommand == null)
                {
                    _editCommitCourseCommand = new RelayCommand(
                        OnEditCommitCourseCommand,
                        () => (CurrentCourse != null));
                }
                return _editCommitCourseCommand;
            }
        }

        private RelayCommand _editCommitCourseCommand;

        private void OnEditCommitCourseCommand()
        {
            if (CurrentCourse != null)
            {
                if (CourseFormInEdit)
                {
                    // if passed validation, end editing
                    if (!CurrentCourseHasErrors && CurrentCourse.TryValidate())
                    {
                        CourseFormEndEdit();
                        // if this is a new course, add to the CoursesList
                        if (CurrentCourse.ChangeTracker.State == ObjectState.Added)
                        {
                            var alreadyAdded = AllCourses.Any(n => n.CourseId == CurrentCourse.CourseId);
                            if (!alreadyAdded)
                            {
                                AllCourses.Add(CurrentCourse);
                                AllCoursesSource.View.MoveCurrentTo(CurrentCourse);
                            }
                        }
                    }
                }
                else
                {
                    CourseFormBeginEdit();
                }
            }
        }

        /// <summary>
        /// Cancel edit an course. We can cancel edit an course
        /// when current course is not null, and the course form
        /// is currently in edit
        /// </summary>
        public RelayCommand CancelEditCourseCommand
        {
            get
            {
                if (_cancelEditCourseCommand == null)
                {
                    _cancelEditCourseCommand = new RelayCommand(
                        OnCancelEditCourseCommand,
                        () => (CurrentCourse != null) && CourseFormInEdit);
                }
                return _cancelEditCourseCommand;
            }
        }

        private RelayCommand _cancelEditCourseCommand;

        private void OnCancelEditCourseCommand()
        {
            if (CurrentCourse != null)
            {
                CourseFormCancelEdit();
                // if this is a new course, simply discard that record
                if (CurrentCourse.ChangeTracker.State == ObjectState.Added)
                {
                    var alreadyAdded = AllCourses.Any(n => n.CourseId == CurrentCourse.CourseId);
                    if (!alreadyAdded)
                    {
                        if (EnrollmentFormInEdit) EnrollmentFormEndEdit();
                        AllCoursesSourceView_CurrentChanged(this, null);
                    }
                }
            }
        }

        /// <summary>
        /// Add enrollment command. We can add a new enrollment
        /// when current course is not null, there are some
        /// students to be selected from and the enrollment form
        /// is not in edit
        /// </summary>
        public RelayCommand AddEnrollmentCommand
        {
            get
            {
                if (_addEnrollmentCommand == null)
                {
                    _addEnrollmentCommand = new RelayCommand(
                        OnAddEnrollmentCommand,
                        () => (CurrentCourse != null) && (_allStudents != null)
                            && (_allStudents.Count > 0) && !EnrollmentFormInEdit);
                }
                return _addEnrollmentCommand;
            }
        }

        private RelayCommand _addEnrollmentCommand;

        private void OnAddEnrollmentCommand()
        {
            if (CurrentCourse != null)
            {
                // create a new enrollment
                CurrentEnrollment = new Enrollment
                {
                    SuspendValidation = true,
                    Course = null,
                    Paid = false
                };
                CurrentEnrollment.SuspendValidation = false;
                // and begin edit
                OnEditCommitEnrollmentCommand();
            }
        }

        /// <summary>
        /// Delete enrollment command. We can delete an enrollment
        /// when current enrollment is not null, and the
        /// enrollment form is not in edit
        /// </summary>
        public RelayCommand DeleteEnrollmentCommand
        {
            get
            {
                if (_deleteEnrollmentCommand == null)
                {
                    _deleteEnrollmentCommand = new RelayCommand(
                        OnDeleteEnrollmentCommand,
                        () => (CurrentEnrollment != null) && !EnrollmentFormInEdit);
                }
                return _deleteEnrollmentCommand;
            }
        }

        private RelayCommand _deleteEnrollmentCommand;

        private void OnDeleteEnrollmentCommand()
        {
            if (CurrentEnrollment != null)
            {
                CurrentEnrollment.MarkAsDeleted();
            }
        }

        /// <summary>
        /// Edit/Commit an course. We can edit/commit an enrollment
        /// when current enrollment is not null
        /// </summary>
        public RelayCommand EditCommitEnrollmentCommand
        {
            get
            {
                if (_editCommitEnrollmentCommand == null)
                {
                    _editCommitEnrollmentCommand = new RelayCommand(
                        OnEditCommitEnrollmentCommand,
                        () => (CurrentEnrollment != null));
                }
                return _editCommitEnrollmentCommand;
            }
        }

        private RelayCommand _editCommitEnrollmentCommand;

        private void OnEditCommitEnrollmentCommand()
        {
            if (CurrentEnrollment != null)
            {
                if (EnrollmentFormInEdit)
                {
                    // if passed validation, end editing
                    if (!CurrentEnrollmentHasErrors && CurrentEnrollment.TryValidate())
                    {
                        EnrollmentFormEndEdit();
                        // if this is a new enrollment, add to CurrentCourse.Enrollments
                        if (CurrentEnrollment.ChangeTracker.State == ObjectState.Added)
                        {
                            var alreadyAdded = CurrentEnrollment.Course != null;
                            if (!alreadyAdded)
                            {
                                // add to the CurrentCourse 
                                CurrentEnrollment.Course = CurrentCourse;
                                // add navigation property Student
                                var student = _allStudents
                                    .First(n => n.PersonId == CurrentEnrollment.StudentId);
                                var currentStudent = new Student
                                                         {
                                                             PersonId = student.PersonId,
                                                             Name = student.Name,
                                                             EnrollmentDate = student.EnrollmentDate,
                                                             Version = student.Version
                                                         };
                                CurrentEnrollment.Student = currentStudent;
                                currentStudent.MarkAsUnchanged();
                                EnrollmentsSource.View.MoveCurrentTo(CurrentEnrollment);
                            }
                        }
                    }
                }
                else
                {
                    EnrollmentFormBeginEdit();
                }
            }
        }

        /// <summary>
        /// Cancel edit an enrollment. We can cancel edit an enrollment
        /// when current enrollment is not null, and the 
        /// enrollment form is currently in edit
        /// </summary>
        public RelayCommand CancelEditEnrollmentCommand
        {
            get
            {
                if (_cancelEditEnrollmentCommand == null)
                {
                    _cancelEditEnrollmentCommand = new RelayCommand(
                        OnCancelEditEnrollmentCommand,
                        () => (CurrentEnrollment != null) && EnrollmentFormInEdit);
                }
                return _cancelEditEnrollmentCommand;
            }
        }

        private RelayCommand _cancelEditEnrollmentCommand;

        private void OnCancelEditEnrollmentCommand()
        {
            if (CurrentEnrollment != null)
            {
                EnrollmentFormCancelEdit();
                // if this is a new enrollment, simply discard that record
                if (CurrentEnrollment.ChangeTracker.State == ObjectState.Added)
                {
                    var alreadyAdded = CurrentEnrollment.Course != null;
                    if (!alreadyAdded)
                    {
                        EnrollmentsSourceView_CurrentChanged(this, null);
                    }
                }
            }
        }

        /// <summary>
        /// Refresh current course command. We can refresh
        /// current course when neither course nor enrollment
        /// form is in edit, and there is no change to save for 
        /// the current course
        /// </summary>
        public RelayCommand RefreshCourseCommand
        {
            get
            {
                if (_refreshCourseCommand == null)
                {
                    _refreshCourseCommand = new RelayCommand(
                        OnRefreshCourseCommand,
                        () => !CourseFormInEdit && !EnrollmentFormInEdit &&
                            (_schoolModel != null) && !(_schoolModel.CurrentCourseHasChanges));
                }
                return _refreshCourseCommand;
            }
        }

        private RelayCommand _refreshCourseCommand;

        private void OnRefreshCourseCommand()
        {
            if (CurrentCourse != null)
            {
                _schoolModel.GetCourseByIdAsync(CurrentCourse.CourseId);
            }
        }

        /// <summary>
        /// Submit change command. We can submit changes
        /// when neither course nor enrollment form is in edit,
        /// and there are changes to save for current course
        /// </summary>
        public RelayCommand SubmitCourseChangeCommand
        {
            get
            {
                if (_submitCourseChangeCommand == null)
                {
                    _submitCourseChangeCommand = new RelayCommand(
                        OnSubmitCourseChangeCommand,
                        () => !CourseFormInEdit && !EnrollmentFormInEdit &&
                            (_schoolModel != null) && (_schoolModel.CurrentCourseHasChanges));
                }
                return _submitCourseChangeCommand;
            }
        }

        private RelayCommand _submitCourseChangeCommand;

        private void OnSubmitCourseChangeCommand()
        {
            try
            {
                if (!_schoolModel.IsBusy && CurrentCourse != null)
                {
                    // we only save changes when current course and its enrollments passed validation
                    var passedValidation = CurrentCourse.TryValidateObjectGraph();
                    if (!passedValidation) return;

                    // save changes for CurrentCourse only 
                    _schoolModel.SaveCourseChangesAsync(false);
                }
            }
            catch (Exception ex)
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(ex);
            }
        }

        /// <summary>
        /// Cancel change command. We can cancel changes
        /// when neither course nor enrollment form is in edit,
        /// and there are changes to cancel for current course
        /// </summary>
        public RelayCommand CancelCourseChangeCommand
        {
            get
            {
                if (_cancelCourseChangeCommand == null)
                {
                    _cancelCourseChangeCommand = new RelayCommand(
                        OnCancelCourseChangeCommand,
                        () => !CourseFormInEdit && !EnrollmentFormInEdit &&
                            (_schoolModel != null) && (_schoolModel.CurrentCourseHasChanges));
                }
                return _cancelCourseChangeCommand;
            }
        }

        private RelayCommand _cancelCourseChangeCommand;

        private void OnCancelCourseChangeCommand()
        {
            try
            {
                if (!_schoolModel.IsBusy && CurrentCourse != null)
                {
                    // ask to confirm canceling changes
                    DialogMessage dialogMessage = new DialogMessage(
                        this,
                        ApplicationStrings.CancelAnyChangesMessageBoxText,
                        s =>
                        {
                            if (s == MessageBoxResult.OK)
                            {
                                // if confirmed, cancel changes for CurrentCourse
                                _schoolModel.RejectCourseChanges(false);
                            }
                        })
                    {
                        Button = MessageBoxButton.OKCancel,
                        Caption = ApplicationStrings.ConfirmMessageBoxCaption
                    };

                    AppMessages.PleaseConfirmMessage.Send(dialogMessage);
                }
            }
            catch (Exception ex)
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(ex);
            }
        }

        /// <summary>
        /// Refresh course list command. We can refresh course list
        ///  when neither course nor enrollment form is in edit, 
        /// and there is no change to save
        /// </summary>
        public RelayCommand RefreshAllCommand
        {
            get
            {
                if (_refreshAllCommand == null)
                {
                    _refreshAllCommand = new RelayCommand(
                        OnRefreshAllCommand,
                        () => !CourseFormInEdit && !EnrollmentFormInEdit &&
                            (_schoolModel != null) && !(_schoolModel.CoursesListHasChanges));
                }
                return _refreshAllCommand;
            }
        }

        private RelayCommand _refreshAllCommand;

        private void OnRefreshAllCommand()
        {
            // get students
            _schoolModel.GetStudentsAsync("None", "CoursePage");
            // get instructors
            _schoolModel.GetInstructorsAsync("None", "CoursePage");
            // get courses
            _schoolModel.GetCoursesAsync("CoursePage");
        }

        /// <summary>
        /// Submit change command. We can submit changes
        /// when neither course nor enrollment form is in edit,
        /// and there are changes to save
        /// </summary>
        public RelayCommand SubmitAllChangeCommand
        {
            get
            {
                if (_submitAllChangeCommand == null)
                {
                    _submitAllChangeCommand = new RelayCommand(
                        OnSubmitAllChangeCommand,
                        () => !CourseFormInEdit && !EnrollmentFormInEdit &&
                            (_schoolModel != null) && (_schoolModel.CoursesListHasChanges));
                }
                return _submitAllChangeCommand;
            }
        }

        private RelayCommand _submitAllChangeCommand;

        private void OnSubmitAllChangeCommand()
        {
            try
            {
                if (!_schoolModel.IsBusy)
                {
                    if (AllCourses != null)
                    {
                        // we only save changes when all courses and their enrollments passed validation
                        var passedValidation = AllCourses.All(o => o.TryValidateObjectGraph());
                        if (!passedValidation) return;

                        // save changes for CoursesList
                        _schoolModel.SaveCourseChangesAsync();
                    }
                }
            }
            catch (Exception ex)
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(ex);
            }
        }

        /// <summary>
        /// Cancel change command. We can cancel changes
        /// when neither course nor enrollment form is in edit,
        /// and there are changes to cancel
        /// </summary>
        public RelayCommand CancelAllChangeCommand
        {
            get
            {
                if (_cancelAllChangeCommand == null)
                {
                    _cancelAllChangeCommand = new RelayCommand(
                        OnCancelAllChangeCommand,
                        () => !CourseFormInEdit && !EnrollmentFormInEdit &&
                            (_schoolModel != null) && (_schoolModel.CoursesListHasChanges));
                }
                return _cancelAllChangeCommand;
            }
        }

        private RelayCommand _cancelAllChangeCommand;

        private void OnCancelAllChangeCommand()
        {
            try
            {
                if (!_schoolModel.IsBusy)
                {
                    // ask to confirm canceling changes
                    DialogMessage dialogMessage = new DialogMessage(
                        this,
                        ApplicationStrings.CancelAnyChangesMessageBoxText,
                        s =>
                        {
                            if (s == MessageBoxResult.OK)
                            {
                                // if confirmed, cancel changes for CoursesList
                                _schoolModel.RejectCourseChanges();
                            }
                        })
                    {
                        Button = MessageBoxButton.OKCancel,
                        Caption = ApplicationStrings.ConfirmMessageBoxCaption
                    };

                    AppMessages.PleaseConfirmMessage.Send(dialogMessage);
                }
            }
            catch (Exception ex)
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(ex);
            }
        }

        #endregion "Public Commands"

        #region "Private Methods"

        /// <summary>
        /// CourseListIsEnabled is set to true only when
        /// course is not in edit and enrollment is also not
        /// in edit
        /// </summary>
        private void UpdateCourseListIsEnabled()
        {
            CourseListIsEnabled = !CourseFormInEdit && !EnrollmentFormInEdit;
        }

        /// <summary>
        /// EnrollmentListIsEnabled is set to true only when
        /// enrollment is not in edit
        /// </summary>
        private void UpdateEnrollmentListIsEnabled()
        {
            EnrollmentListIsEnabled = !EnrollmentFormInEdit;
        }

        /// <summary>
        /// StudentComboIsEditable is set to true only when
        /// enrollment is in edit and a new enrollment has just get
        /// created
        /// </summary>
        private void UpdateStudentComboIsEditable()
        {
            StudentComboIsEditable = EnrollmentFormInEdit && CurrentEnrollment != null &&
                                        CurrentEnrollment.ChangeTracker.State == ObjectState.Added &&
                                        CurrentEnrollment.Course == null;
        }

        private void CourseFormBeginEdit()
        {
            if (CurrentCourse != null)
            {
                CurrentCourse.BeginEdit();
                AppMessages.BeginEditMessage.Send("Course");
                CourseFormInEdit = true;
            }
        }

        private void CourseFormEndEdit()
        {
            AppMessages.EndEditMessage.Send("Course");
            CourseFormInEdit = false;
            if (CurrentCourse != null) CurrentCourse.EndEdit();
        }

        private void CourseFormCancelEdit()
        {
            if (CurrentCourse != null)
            {
                AppMessages.CancelEditMessage.Send("Course");
                CourseFormInEdit = false;
                CurrentCourse.CancelEdit();
            }
        }

        private void EnrollmentFormBeginEdit()
        {
            if (CurrentEnrollment != null)
            {
                CurrentEnrollment.BeginEdit();
                AppMessages.BeginEditMessage.Send("Enrollment");
                EnrollmentFormInEdit = true;
            }
        }

        private void EnrollmentFormEndEdit()
        {
            AppMessages.EndEditMessage.Send("Enrollment");
            EnrollmentFormInEdit = false;
            if (CurrentEnrollment != null) CurrentEnrollment.EndEdit();
        }

        private void EnrollmentFormCancelEdit()
        {
            if (CurrentEnrollment != null)
            {
                AppMessages.CancelEditMessage.Send("Enrollment");
                EnrollmentFormInEdit = false;
                CurrentEnrollment.CancelEdit();
            }
        }

        /// <summary>
        /// Event handler for GetStudentsCompleted
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _schoolModel_GetStudentsCompleted(object sender, ResultsArgs<Student> e)
        {
            var screenName = e.UserState as string;
            if (!string.Equals(screenName, "CoursePage")) return;

            if (!e.HasError)
            {
                // clear any previous error after a successful call
                _schoolModel.ClearLastError();
                // sort by student name
                _allStudents = new ObservableCollection<Student>(e.Results.OrderBy(n => n.Name));

                AllStudentsSource = new CollectionViewSource {Source = _allStudents};
                AllStudentsSource.Filter += AllStudentsSource_Filter;
            }
            else
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(e.Error);
            }
        }

        /// <summary>
        /// Event handler for Filter
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void AllStudentsSource_Filter(object sender, FilterEventArgs e)
        {
            Student item = e.Item as Student;
            if (item != null && CurrentCourse != null)
            {
                e.Accepted = !CurrentCourse.Enrollments.Any(n => n.StudentId == item.PersonId) ||
                             ((CurrentEnrollment == null) || (CurrentEnrollment.StudentId == item.PersonId));
            }
        }

        /// <summary>
        /// Event handler for GetInstructorsCompleted
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _schoolModel_GetInstructorsCompleted(object sender, ResultsArgs<Instructor> e)
        {
            var screenName = e.UserState as string;
            if (!string.Equals(screenName, "CoursePage")) return;

            if (!e.HasError)
            {
                // clear any previous error after a successful call
                _schoolModel.ClearLastError();
                // sort by instructor name
                _allInstructors = new ObservableCollection<Instructor>(e.Results.OrderBy(n => n.Name));

                AllInstructorsSource = new CollectionViewSource {Source = _allInstructors};
            }
            else
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(e.Error);
            }
        }

        /// <summary>
        /// Event handler for GetCoursesCompleted
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _schoolModel_GetCoursesCompleted(object sender, ResultsArgs<Course> e)
        {
            var screenName = e.UserState as string;
            if (!string.Equals(screenName, "CoursePage")) return;

            if (!e.HasError)
            {
                // clear any previous error after a successful call
                _schoolModel.ClearLastError();

                // cancel any changes before setting AllCoursesSource
                if (_schoolModel.CoursesListHasChanges)
                {
                    _schoolModel.RejectCourseChanges();
                }

                AllCourses = new ObservableCollection<Course>(e.Results);
                AllCoursesSource = new CollectionViewSource {Source = AllCourses};
                // sort by CourseId
                AllCoursesSource.SortDescriptions.Add(new SortDescription("CourseId", ListSortDirection.Ascending));
                AllCoursesSource.View.CurrentChanged += AllCoursesSourceView_CurrentChanged;

                if (AllCourses.Count >= 1)
                {
                    if (CurrentCourse != null)
                    {
                        var currentCourse = AllCourses
                            .FirstOrDefault(n => n.CourseId == CurrentCourse.CourseId);
                        if (currentCourse != null)
                            AllCoursesSource.View.MoveCurrentTo(currentCourse);
                        else
                            // set the first row as the current course in edit
                            AllCoursesSource.View.MoveCurrentToFirst();
                    }
                    else
                    {
                        // set the first row as the current course in edit
                        AllCoursesSource.View.MoveCurrentToFirst();
                    }
                    // assign the current item to CurrentCourse
                    CurrentCourse = (Course) AllCoursesSource.View.CurrentItem;
                    // set EnrollmentsSource
                    if (CurrentCourse != null)
                    {
                        EnrollmentsSource = new CollectionViewSource {Source = CurrentCourse.Enrollments};
                        // sort by EnrollmentId
                        EnrollmentsSource.SortDescriptions.Add(new SortDescription("EnrollmentId", ListSortDirection.Ascending));
                        EnrollmentsSource.View.CurrentChanged += EnrollmentsSourceView_CurrentChanged;
                        // set the first row as the current enrollment in edit
                        if (CurrentCourse.Enrollments != null && CurrentCourse.Enrollments.Count >= 1)
                        {
                            EnrollmentsSource.View.MoveCurrentToFirst();
                            CurrentEnrollment = (Enrollment) EnrollmentsSource.View.CurrentItem;
                        }
                        else
                        {
                            CurrentEnrollment = null;
                        }
                    }
                }
                else
                {
                    CurrentCourse = null;
                    EnrollmentsSource = new CollectionViewSource();
                    CurrentEnrollment = null;
                }
            }
            else
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(e.Error);
            }
        }

        /// <summary>
        /// Event handler for CurrentChanged
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void AllCoursesSourceView_CurrentChanged(object sender, EventArgs e)
        {
            CurrentCourse = (Course) AllCoursesSource.View.CurrentItem;
            // set EnrollmentsSource
            if (CurrentCourse != null)
            {
                EnrollmentsSource = new CollectionViewSource {Source = CurrentCourse.Enrollments};
                // sort by EnrollmentId
                EnrollmentsSource.SortDescriptions.Add(new SortDescription("EnrollmentId", ListSortDirection.Ascending));
                EnrollmentsSource.View.CurrentChanged += EnrollmentsSourceView_CurrentChanged;
                // set the current enrollment in edit
                if (CurrentCourse.Enrollments != null && CurrentCourse.Enrollments.Count >= 1)
                {
                    CurrentEnrollment = (Enrollment) EnrollmentsSource.View.CurrentItem;
                }
                else
                {
                    CurrentEnrollment = null;
                }
            }
            else
            {
                EnrollmentsSource = new CollectionViewSource();
                CurrentEnrollment = null;
            }
        }

        /// <summary>
        /// Event handler for CurrentChanged
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void EnrollmentsSourceView_CurrentChanged(object sender, EventArgs e)
        {
            CurrentEnrollment = (Enrollment) EnrollmentsSource.View.CurrentItem;
        }

        /// <summary>
        /// Event handler for GetCourseByIdCompleted
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _schoolModel_GetCourseByIdCompleted(object sender, ResultArgs<Course> e)
        {
            if (!e.HasError)
            {
                // clear any previous error after a successful call
                _schoolModel.ClearLastError();

                Course currentCourse = e.Results;
                if (currentCourse != null)
                {
                    // find the matching current course from AllCourses list
                    Course matchedCourse = AllCourses.Single(n => n.CourseId == currentCourse.CourseId);
                    // replace matchedCourse from AllCourses list with what is returned from GetCourseById
                    int index = AllCourses.IndexOf(matchedCourse);
                    AllCourses.Remove(matchedCourse);
                    AllCourses.Insert(index, currentCourse);
                    AllCoursesSource.View.MoveCurrentTo(currentCourse);
                }
                else
                {
                    DialogMessage dialogMessage = new DialogMessage(
                        this,
                        ErrorResources.CurrentCourseDoesNotExistMessageBoxText,
                        null)
                    {
                        Button = MessageBoxButton.OK,
                        Caption = ApplicationStrings.WarningMessageBoxCaption
                    };

                    AppMessages.StatusUpdateMessage.Send(dialogMessage);
                }
            }
            else
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(e.Error);
            }
        }

        /// <summary>
        /// Event handler for SaveCourseChangesCompleted
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _schoolModel_SaveCourseChangesCompleted(object sender, ResultArgs<string> e)
        {
            if (!e.HasError)
            {
                // clear any previous error after a successful call
                _schoolModel.ClearLastError();

                // check whether there is any warning message returned
                if (!string.IsNullOrEmpty(e.Results))
                {
                    DialogMessage dialogMessage = new DialogMessage(
                        this,
                        e.Results,
                        null)
                    {
                        Button = MessageBoxButton.OK,
                        Caption = ApplicationStrings.WarningMessageBoxCaption
                    };

                    AppMessages.StatusUpdateMessage.Send(dialogMessage);

                    // If last operation is a delete operation, call reject changes
                    if (CurrentCourse != null && CurrentCourse.ChangeTracker.State == ObjectState.Deleted)
                    {
                        _schoolModel.RejectCourseChanges(false);
                    }
                }
                else
                {
                    if (_schoolModel.CoursesListHasChanges)
                    {
                        if (!_schoolModel.CurrentCourseHasChanges)
                            // only refresh current course after Insert/Update/Delete
                            OnRefreshCourseCommand();
                    }
                    else
                        // refresh the CoursesList after Insert/Update/Delete
                        OnRefreshAllCommand();
                }
            }
            else
            {
                // notify user if there is any error
                AppMessages.RaiseErrorMessage.Send(e.Error);
            }
        }

        /// <summary>
        /// Event handler for PropertyChanged
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _schoolModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "CoursesListHasChanges":
                    RefreshAllCommand.RaiseCanExecuteChanged();
                    SubmitAllChangeCommand.RaiseCanExecuteChanged();
                    CancelAllChangeCommand.RaiseCanExecuteChanged();
                    break;
                case "CurrentCourseHasChanges":
                    RefreshCourseCommand.RaiseCanExecuteChanged();
                    SubmitCourseChangeCommand.RaiseCanExecuteChanged();
                    CancelCourseChangeCommand.RaiseCanExecuteChanged();
                    break;
            }
        }

        /// <summary>
        /// Event handler for PropertyChanged
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CoursePageViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "CurrentCourse":
                    AddEnrollmentCommand.RaiseCanExecuteChanged();
                    DeleteCourseCommand.RaiseCanExecuteChanged();
                    EditCommitCourseCommand.RaiseCanExecuteChanged();
                    CancelEditCourseCommand.RaiseCanExecuteChanged();
                    break;
                case "CurrentEnrollment":
                    DeleteEnrollmentCommand.RaiseCanExecuteChanged();
                    EditCommitEnrollmentCommand.RaiseCanExecuteChanged();
                    CancelEditEnrollmentCommand.RaiseCanExecuteChanged();
                    UpdateStudentComboIsEditable();
                    if (AllStudentsSource != null && AllStudentsSource.View != null)
                        AllStudentsSource.View.Refresh();
                    break;
                case "AllStudentsSource":
                    AddEnrollmentCommand.RaiseCanExecuteChanged();
                    break;
                case "CourseFormInEdit":
                    AddCourseCommand.RaiseCanExecuteChanged();
                    DeleteCourseCommand.RaiseCanExecuteChanged();
                    CancelEditCourseCommand.RaiseCanExecuteChanged();
                    RefreshCourseCommand.RaiseCanExecuteChanged();
                    SubmitCourseChangeCommand.RaiseCanExecuteChanged();
                    CancelCourseChangeCommand.RaiseCanExecuteChanged();
                    RefreshAllCommand.RaiseCanExecuteChanged();
                    SubmitAllChangeCommand.RaiseCanExecuteChanged();
                    CancelAllChangeCommand.RaiseCanExecuteChanged();
                    UpdateCourseListIsEnabled();
                    break;
                case "EnrollmentFormInEdit":
                    AddCourseCommand.RaiseCanExecuteChanged();
                    DeleteCourseCommand.RaiseCanExecuteChanged();
                    AddEnrollmentCommand.RaiseCanExecuteChanged();
                    DeleteEnrollmentCommand.RaiseCanExecuteChanged();
                    CancelEditEnrollmentCommand.RaiseCanExecuteChanged();
                    RefreshCourseCommand.RaiseCanExecuteChanged();
                    SubmitCourseChangeCommand.RaiseCanExecuteChanged();
                    CancelCourseChangeCommand.RaiseCanExecuteChanged();
                    RefreshAllCommand.RaiseCanExecuteChanged();
                    SubmitAllChangeCommand.RaiseCanExecuteChanged();
                    CancelAllChangeCommand.RaiseCanExecuteChanged();
                    UpdateCourseListIsEnabled();
                    UpdateEnrollmentListIsEnabled();
                    UpdateStudentComboIsEditable();
                    break;
            }
        }

        #endregion "Private Methods"
    }
}

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)
United States United States
Weidong has been an information system professional since 1990. He has a Master's degree in Computer Science, and is currently a MCSD .NET

Comments and Discussions