Intersoft ClientUI Documentation
SaveChangesCommand Property (UXScheduleView)



Gets or sets a command that invoked when saving all the changes.
Syntax
<TypeConverterAttribute("Intersoft.Client.Framework.Input.CommandConverter, Intersoft.Client.Framework, Version=3.0.5000.1, Culture=neutral, PublicKeyToken=c3d9b11444163e76")>
<CategoryAttribute("Action")>
Public Property SaveChangesCommand As ICommand
Dim instance As UXScheduleView
Dim value As ICommand
 
instance.SaveChangesCommand = value
 
value = instance.SaveChangesCommand
[TypeConverterAttribute("Intersoft.Client.Framework.Input.CommandConverter, Intersoft.Client.Framework, Version=3.0.5000.1, Culture=neutral, PublicKeyToken=c3d9b11444163e76")]
[CategoryAttribute("Action")]
public ICommand SaveChangesCommand {get; set;}
[TypeConverterAttribute("Intersoft.Client.Framework.Input.CommandConverter, Intersoft.Client.Framework, Version=3.0.5000.1, Culture=neutral, PublicKeyToken=c3d9b11444163e76")]
[CategoryAttribute("Action")]
public:
property ICommand^ SaveChangesCommand {
   ICommand^ get();
   void set (    ICommand^ value);
}
Remarks

To handle the Create, Update, and Delete (CUD) operation, UXScheduleView provides several command-related properties that you can bind to your ViewModel to execute the method depending on the action. These command-related properties are listed as follows:

Command Sequences

Create operation

The following commands are called in sequence when an event or an exception is created:

Update Operation

The following commands are called in sequence when an event is updated:

Delete Operation

The following commands are called in sequence when one or multiple events are deleted:

When you edited an occurrence of recurring event, it doesn't actually perform an update operation. If the occurrence is not an exception, it will create an exception by triggering the create operation. Similar approach is applied when you deleted an occurrence of recurring event.

Example

The following code example shows how to define and bind the editing commands from ViewModel to UXScheduleView.

ScheduleViewModelGenericBase
Copy Code
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.ServiceModel.DomainServices.Client;
using Intersoft.Client.Data.ComponentModel;
using Intersoft.Client.Framework;
using UXScheduleView.Samples.ModelServices;

namespace UXScheduleView.Samples.ViewModels
{
    public class ScheduleViewModelBase<T> : ValidationViewModelBase where T : Entity
    {
        #region Fields

        private IEnumerable _categories;
        private IEnumerable _events;
        private IEnumerable _resources;

        private bool _isBusy;
        private bool _isPrerequisiteDataLoaded;
        private bool _isCategoriesLoaded;
        private bool _isResourcesLoaded;

        private T _selectedEvent;
        private IEnumerable<T> _selectedEvents;
        private QueryDescriptor _queryDescriptor;

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the <see cref="ScheduleViewModelBase"/> class.
        /// </summary>
        public ScheduleViewModelBase()
        {
            this.QueryDescriptor = new QueryDescriptor();
            this.Presenter = new MessagePresenter();

            this.QueryLatency = 0.6;
            
            if (!this.IsInDesignMode)
            {
                this.IsBusy = true;
                this.LoadCategoriesData();
                this.LoadResourcesData();
            }
        }

        #endregion

        #region Data Source

        /// <summary>
        /// Gets the categories data repository instance that implements <see cref="IDataRepository"/>.
        /// </summary>
        protected virtual IDataRepository CategoriesDataSource { get; private set; }

        /// <summary>
        /// Gets the events data repository instance that implements <see cref="IDataRepository"/>.
        /// </summary>
        protected virtual IDataRepository EventsDataSource { get; private set; }

        /// <summary>
        /// Gets the resources data repository instance that implements <see cref="IDataRepository"/>.
        /// </summary>
        protected virtual IDataRepository ResourcesDataSource { get; private set; }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets a value representing the collection of category data.
        /// </summary>
        public IEnumerable Categories
        {
            get { return _categories; }
            set
            {
                if (_categories != value)
                {
                    _categories = value;
                    OnPropertyChanged("Categories");
                }
            }
        }

        /// <summary>
        /// Gets or sets a value representing the collection of event data.
        /// </summary>
        public IEnumerable Events
        {
            get { return _events; }
            set
            {
                if (_events != value)
                {
                    _events = value;
                    OnPropertyChanged("Events");
                }
            }
        }

        /// <summary>
        /// Gets or sets a value representing the collection of resource data.
        /// </summary>
        public IEnumerable Resources
        {
            get { return _resources; }
            set
            {
                if (_resources != value)
                {
                    _resources = value;
                    OnPropertyChanged("Resources");
                }
            }
        }

        /// <summary>
        /// Gets or sets a value that indicates whether the data repository is busy processing a query based on the given <see cref="QueryDescriptor"/>.
        /// </summary>
        public bool IsBusy
        {
            get { return _isBusy; }
            set
            {
                if (_isBusy != value)
                {
                    _isBusy = value;
                    OnPropertyChanged("IsBusy");
                }
            }
        }

        /// <summary>
        /// Gets a value that indicates whether the application is currently in design-time mode.
        /// </summary>
        protected bool IsInDesignMode
        {
            get { return Intersoft.Client.Framework.ISControl.IsInDesignModeStatic; }
        }

        /// <summary>
        /// Gets or sets a value that indicates whether the prerequisite data is loaded.
        /// </summary>        
        protected virtual bool IsPrerequisiteDataLoaded
        {
            get { return _isPrerequisiteDataLoaded; }
            set
            {
                if (_isPrerequisiteDataLoaded != value)
                {
                    _isPrerequisiteDataLoaded = value;
                    OnPropertyChanged("IsPrerequisiteDataLoaded");

                    if (value)
                        this.QueryDescriptor.RaiseQueryChanged();
                }
            }
        }

        public bool IsCategoriesLoaded
        {
            get { return _isCategoriesLoaded; }
            set
            {
                if (_isCategoriesLoaded != value)
                {
                    _isCategoriesLoaded = value;
                    OnPropertyChanged("IsCategoriesLoaded");

                    if (value)
                        this.NotifyPrerequisiteDataLoaded();
                }
            }
        }

        public bool IsResourcesLoaded
        {
            get { return _isResourcesLoaded; }
            set
            {
                if (_isResourcesLoaded != value)
                {
                    _isResourcesLoaded = value;
                    OnPropertyChanged("IsResourcesLoaded");

                    if (value)
                        this.NotifyPrerequisiteDataLoaded();
                }
            }
        }

        /// <summary>
        /// Gets the <see cref="MessagePresenter"/> instance.
        /// </summary>
        protected virtual MessagePresenter Presenter { get; private set; }

        /// <summary>
        /// Gets or sets a <see cref="QueryDescriptor"/> instance which provides the required information for data query purpose.
        /// </summary>
        public QueryDescriptor QueryDescriptor
        {
            get
            {
                return _queryDescriptor;
            }
            set
            {
                if (_queryDescriptor != value)
                {
                    if (_queryDescriptor != null)
                        _queryDescriptor.QueryChanged -= new EventHandler(OnQueryChanged);

                    _queryDescriptor = value;
                    _queryDescriptor.QueryChanged += new EventHandler(OnQueryChanged);

                    OnPropertyChanged("QueryDescriptor");
                }
            }
        }

        private double QueryLatency { get; set; }

        /// <summary>
        /// Gets or sets a value indicating the currently selected item.
        /// </summary>
        public T SelectedEvent
        {
            get { return _selectedEvent; }
            set
            {
                if (_selectedEvent != value)
                {
                    if (_selectedEvent != null)
                        _selectedEvent.PropertyChanged -= new PropertyChangedEventHandler(OnSelectedEventPropertyChanged);

                    T _oldItem = _selectedEvent;
                    _selectedEvent = value;
                    OnSelectedEventChanged(_oldItem, value);

                    if (_selectedEvent != null)
                        _selectedEvent.PropertyChanged += new PropertyChangedEventHandler(OnSelectedEventPropertyChanged);

                    OnPropertyChanged("SelectedEvent");
                }
            }
        }

        /// <summary>
        /// Gets or sets a collection of multiple selected items.
        /// </summary>
        public IEnumerable<T> SelectedEvents
        {
            get { return _selectedEvents; }
            set
            {
                if (_selectedEvents != value)
                {
                    _selectedEvents = value;
                    OnPropertyChanged("SelectedEvents");
                }
            }
        }

        #endregion

        #region Virtual Methods

        /// <summary>
        /// Called when the data repository needs to fetch data from the repository, either during initial load, or due to query change.
        /// </summary>
        /// <param name="dataSource">An instance of the data repository.</param>
        protected virtual void LoadCategoriesData(IDataRepository dataSource)
        {
            if (!this.IsInDesignMode && dataSource == null)
                throw new ArgumentNullException("dataSource should not be null.");

            this.CategoriesDataSource = dataSource;
            this.LoadCategoriesData();
        }

        /// <summary>
        /// Called when the data repository needs to fetch data from the repository, either during initial load, or due to query change.
        /// </summary>
        protected virtual void LoadCategoriesData()
        {
            Utility.ExecuteTimeOut(this.QueryLatency,
            () =>
            {
                if (this.CategoriesDataSource != null)
                {
                    this.IsBusy = true;

                    this.CategoriesDataSource.GetData
                    (
                        (items) =>
                        {
                            this.IsBusy = false;
                            this.IsCategoriesLoaded = true;
                            this.Categories = new PagedCollectionView(items);
                        },
                        (error) =>
                        {
                            this.IsBusy = false;

                            this.Presenter.ShowErrorMessage(
                                "An exception has occurred during data loading.\n" +
                                "Message: " + error.Message + "\n" +
                                "Stack Trace: " + error.StackTrace);
                        }
                    );

                    this.QueryLatency = 0;
                }
            });
        }

        /// <summary>
        /// Called when the data repository needs to fetch data from the repository, either during initial load, or due to query change.
        /// </summary>
        /// <param name="dataSource">An instance of the data repository.</param>
        protected virtual void LoadEventsData(IDataRepository dataSource)
        {
            if (!this.IsInDesignMode && dataSource == null)
                throw new ArgumentNullException("dataSource should not be null.");

            this.EventsDataSource = dataSource;
            this.LoadEventsData();
        }

        /// <summary>
        /// Called when the data repository needs to fetch data from the repository, either during initial load, or due to query change.
        /// </summary>
        protected virtual void LoadEventsData()
        {
            if (this.EventsDataSource != null)
            {
                this.IsBusy = true;

                this.EventsDataSource.GetData
                (
                    this.QueryDescriptor,
                    (items) =>
                    {
                        this.IsBusy = false;
                        this.Events = new PagedCollectionView(items);
                    },
                    (totalItemCount) =>
                    {
                        // do nothing
                    },
                    (error) =>
                    {
                        this.IsBusy = false;

                        this.Presenter.ShowErrorMessage(
                            "An exception has occurred during data loading.\n" +
                            "Message: " + error.Message + "\n" +
                            "Stack Trace: " + error.StackTrace);
                    }
                );
            }
        }

        /// <summary>
        /// Called when the data repository needs to fetch data from the repository, either during initial load, or due to query change.
        /// </summary>
        /// <param name="dataSource">An instance of the data repository.</param>
        protected virtual void LoadResourcesData(IDataRepository dataSource)
        {
            if (!this.IsInDesignMode && dataSource == null)
                throw new ArgumentNullException("dataSource should not be null.");

            this.ResourcesDataSource = dataSource;
            this.LoadResourcesData();
        }

        /// <summary>
        /// Called when the data repository needs to fetch data from the repository, either during initial load, or due to query change.
        /// </summary>
        protected virtual void LoadResourcesData()
        {
            Utility.ExecuteTimeOut(this.QueryLatency,
            () =>
            {
                if (this.ResourcesDataSource != null)
                {
                    this.IsBusy = true;

                    this.ResourcesDataSource.GetData
                    (
                        (items) =>
                        {
                            this.IsBusy = false;
                            this.IsResourcesLoaded = true;
                            this.Resources = new PagedCollectionView(items);
                        },
                        (error) =>
                        {
                            this.IsBusy = false;

                            this.Presenter.ShowErrorMessage(
                                "An exception has occurred during data loading.\n" +
                                "Message: " + error.Message + "\n" +
                                "Stack Trace: " + error.StackTrace);
                        }
                    );

                    this.QueryLatency = 0;
                }
            });
        }


        protected virtual void NotifyPrerequisiteDataLoaded()
        {
            if (this.IsCategoriesLoaded && this.IsResourcesLoaded)
                this.IsPrerequisiteDataLoaded = true;
        }

        /// <summary>
        /// Called when one of the properties in the <see cref="QueryDescriptor"/> object is changed.
        /// </summary>
        /// <param name="sender">The sender of the event.</param>
        /// <param name="e">The data related to the event.</param>
        protected virtual void OnQueryChanged(object sender, EventArgs e)
        {
            // Perform data retrieval in 0.6ms latency to ensure smooth transition. By default, transition took ~0.3ms.
            // If transition is not applied in the View, it's not necessary to use ExecuteTimeOut method.

            Utility.ExecuteTimeOut(this.QueryLatency,
                () =>
                {
                    if (this.IsPrerequisiteDataLoaded)
                    {
                        this.LoadEventsData();
                        this.QueryLatency = 0;
                    }
                });
        }

        /// <summary>
        /// Called when the <see cref="SelectedEvent"/> property changes.
        /// </summary>
        /// <param name="oldItem">The old selected item.</param>
        /// <param name="newItem">The new selected item.</param>
        protected virtual void OnSelectedEventChanged(T oldItem, T newItem)
        {
        }

        /// <summary>
        /// Called when one of the properties in the <see cref="SelectedEvent"/> object is changed.
        /// </summary>
        /// <param name="sender">The sender of the event.</param>
        /// <param name="e">The data related to the event.</param>
        protected virtual void OnSelectedEventPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
        }

        #endregion
    }
}
EditableScheduleViewModelBase
Copy Code
using System.Collections;
using System.ServiceModel.DomainServices.Client;
using Intersoft.Client.Framework.Input;
using Intersoft.Client.UI.ScheduleView;
using UXScheduleView.Samples.ModelServices;

namespace UXScheduleView.Samples.ViewModels
{
    public class EditableScheduleViewModelBase<T> : ScheduleViewModelBase<T> where T : Entity
    {
        #region Constructors

        public EditableScheduleViewModelBase()
            : base()
        {
            this.DeleteItemCommand = new DelegateCommand(ExecuteDeleteItem);
            this.InsertItemCommand = new DelegateCommand(ExecuteInsertItem);
            this.PrepareNewItemCommand = new DelegateCommand(ExecutePrepareNewItem);
            this.SaveChangesCommand = new DelegateCommand(ExecuteSaveChanges);
            this.RefreshCommand = new DelegateCommand(ExecuteRefreshCommand);
            this.RejectChangesCommand = new DelegateCommand(ExecuteRejectChanges);
            this.RejectItemCommand = new DelegateCommand(ExecuteRejectItem);
            this.UpdateItemCommand = new DelegateCommand(ExecuteUpdateItem);
            this.ValidateItemCommand = new DelegateCommand(ExecuteValidateItem, CanValidateItem);
        }

        #endregion

        #region Fields

        private T _newItem;

        #endregion

        #region Properties

        public IEditableDataRepository<T> EditableEventsDataSource
        {
            get { return this.EventsDataSource as IEditableDataRepository<T>; }
        }

        public T NewItem
        {
            get { return this._newItem; }
            set
            {
                if (this._newItem != value)
                {
                    this._newItem = value;
                    this.OnPropertyChanged("NewItem");
                }
            }
        }

        #endregion

        #region Commands

        public DelegateCommand DeleteItemCommand { get; set; }
        public DelegateCommand InsertItemCommand { get; set; }
        public DelegateCommand PrepareNewItemCommand { get; set; }
        public DelegateCommand SaveChangesCommand { get; set; }
        public DelegateCommand RefreshCommand { get; set; }
        public DelegateCommand RejectChangesCommand { get; set; }
        public DelegateCommand RejectItemCommand { get; set; }
        public DelegateCommand UpdateItemCommand { get; set; }
        public DelegateCommand ValidateItemCommand { get; set; }

        #endregion

        #region Methods

        protected virtual bool CanValidateItem(object parameter)
        {
            UXScheduleViewEventModel evtModel = parameter as UXScheduleViewEventModel;
            if (evtModel != null)
            {
                if (string.IsNullOrEmpty(evtModel.Subject))
                {
                    return false;
                }
            }

            return true;
        }

        protected virtual void ExecuteDeleteItem(object parameter)
        {
            IList list = parameter as IList;
            if (list != null)
                this.EditableEventsDataSource.Delete(list);
            else
                this.EditableEventsDataSource.Delete(parameter as T);
        }

        protected virtual void ExecuteInsertItem(object parameter)
        {

        }

        protected virtual void ExecutePrepareNewItem(object parameter)
        {

        }

        protected virtual void ExecuteSaveChanges(object parameter)
        {
            this.IsBusy = true;

            this.EditableEventsDataSource.SaveChanges
            (
                () =>
                {
                    this.IsBusy = false;
                },
                exception =>
                {
                    this.IsBusy = false;

                    this.Presenter.ShowErrorMessage(
                        "An exception has occurred during save changes.\n" +
                        "Message: " + exception.Message + "\n" +
                        "Stack Trace: " + exception.StackTrace);
                }
            );
        }

        protected virtual void ExecuteRefreshCommand(object parameter)
        {
            this.LoadEventsData();
        }

        protected virtual void ExecuteRejectChanges(object parameter)
        {
            this.EditableEventsDataSource.RejectChanges();
        }

        protected virtual void ExecuteRejectItem(object parameter)
        {
            T entity = parameter as T;
            this.EditableEventsDataSource.RejectChanges(entity);
        }

        protected virtual void ExecuteUpdateItem(object parameter)
        {

        }

        protected virtual void ExecuteValidateItem(object parameter)
        {

        }

        #endregion
    }
}
Binding ViewModel to View
Copy Code
<Intersoft:UXScheduleView x:Name="SampleControl1" DisplayDate="1/2/2012"
            IsBusy="{Binding IsBusy, Mode=TwoWay}"
            EventsSource="{Binding Events}" CategoriesSource="{Binding Categories}" ResourcesSource="{Binding Resources}"
            CanUserAddItems="True" CanUserDeleteItems="True" CanUserEditItems="True" CanUserMoveItems="True" CanUserResizeItems="True"
            NewItem="{Binding NewItem, Mode=TwoWay}"
            PrepareNewItemCommand="{Binding PrepareNewItemCommand}" 
            InsertItemCommand="{Binding InsertItemCommand}"
            DeleteItemCommand="{Binding DeleteItemCommand}"
            UpdateItemCommand="{Binding UpdateItemCommand}"
            RejectItemCommand="{Binding RejectItemCommand}"
            ValidateItemCommand="{Binding ValidateItemCommand}"
            SaveChangesCommand="{Binding SaveChangesCommand}"
            RefreshCommand="{Binding RefreshCommand}>
    <Intersoft:UXScheduleDayView/>
    <Intersoft:UXScheduleWorkWeekView/>
    <Intersoft:UXScheduleWeekView IsActive="True"/>
    <Intersoft:UXScheduleMonthView/>
</Intersoft:UXScheduleView>

Handling the CUD operation can be a tedious task in the RIA development due to the repetitive processes. You can use the above generic templates to quickly handle the CUD operation in a more efficient way. The following code shows an example how to use the provided generic templates.

HospitalViewModel
Copy Code
using Intersoft.Client.UI.ScheduleView;
using UXScheduleView.Samples.ModelServices;
using UXScheduleView.Samples.Web;

namespace UXScheduleView.Samples.ViewModels
{
    public class HospitalViewModel : EditableScheduleViewModelBase<HospitalEvent>
    {
        #region Constructors

        public HospitalViewModel()
        {
            
        }

        #endregion

        protected override IDataRepository CategoriesDataSource
        {
            get { return HospitalCategoriesRepository.Instance; }
        }

        protected override IDataRepository EventsDataSource
        {
            get { return HospitalEventsRepository.Instance; }
        }

        protected override IDataRepository ResourcesDataSource
        {
            get { return HospitalResourcesRepository.Instance; }
        }
        
        protected override void ExecutePrepareNewItem(object parameter)
        {
            base.ExecutePrepareNewItem(parameter);

            UXScheduleViewEventModel evtModel = parameter as UXScheduleViewEventModel;
            HospitalEvent evt = this.EditableEventsDataSource.Create();

            if (evtModel.ResourceID == -1)
            {
                if (evtModel.GroupValues.Count > 0)
                {
                    foreach (string key in evtModel.GroupValues.Keys)
                    {
                        switch (key)
                        {
                            case "ResourceID":
                                evt.ResourceID = int.Parse(evtModel.GroupValues[key].ToString());
                                break;
                            case "CategoryID":
                                evt.CategoryID = int.Parse(evtModel.GroupValues[key].ToString());
                                break;
                        }
                    }
                }
                else
                {
                    evt.ResourceID = 1;
                }
            }

            this.NewItem = evt;
            this.EditableEventsDataSource.Insert(evt);
        }
    }
}

As you can see in the code above, you only need to override several properties and methods since most of other operations are already handled in the base class. Feel free to override any of the provided methods and add additional logic to suit your application's requirements.

When ValidateItemCommand return false, trying to lost focus in the current editing item will re-focus the item.
Requirements

Target Platforms: Windows 7, Windows Vista SP1 or later, Windows XP SP3, Windows Server 2008 (Server Core not supported), Windows Server 2008 R2 (Server Core supported with SP1 or later), Windows Server 2003 SP2

See Also

Reference

UXScheduleView Class
UXScheduleView Members

Send Feedback