This is a migrated thread and some comments may be shown as answers.

Custom Appointment Validation

4 Answers 183 Views
ScheduleView
This is a migrated thread and some comments may be shown as answers.
Art Kedzierski
Top achievements
Rank 2
Art Kedzierski asked on 09 Sep 2013, 03:47 PM
Where is the appropriate point in the event stream to validate a custom appointment? I found a post from two years ago that suggests attaching to the edit dialog's RadButton click event, but it also mentioned that you were planning some sort of validation mechanism. Also, I'm using MVVM and not code-behind as suggested in that thread.

What's the status on that validation mechanism?

4 Answers, 1 is accepted

Sort by
0
Yana
Telerik team
answered on 11 Sep 2013, 01:10 PM
Hello Art,

You could check how the validation is implemented in our RadScheduleVIew Custom Appointment and Validation online example at the following link:
http://demos.telerik.com/silverlight/#ScheduleView/CustomAppointmentAndValidation

The idea is that the CustomAppointment class implements IDataErrorInfo interface.
Please review the example and if you have any questions/issues with it, write to us again.

Regards,
Yana
Telerik
TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for SILVERLIGHT.
Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
Sign up for Free application insights >>
0
Art Kedzierski
Top achievements
Rank 2
answered on 11 Sep 2013, 05:06 PM
That works, thanks!

I am having one little issue: when Category is set to a specific value, I want one of my custom fields to then become required. However, the validation visual (red-lined box) only appears around the text-box in question if text is entered and then deleted from it. How can I check a secondary field in the Category validation?

private string ValidateCategory()
{
    if (string.IsNullOrEmpty(this.Category.DisplayName))
    {
        return "Please select an appointment category!";
    }
    if (this.Category.DisplayName == "Case-Related")
    {
        // Validate CaseID field ???
    }
    return null;
}
0
Art Kedzierski
Top achievements
Rank 2
answered on 11 Sep 2013, 08:14 PM
Another issue, this works fine for existing appointments, but when I try to create a new appointment I get the following errors (twice). It happens when I cancel the appointment dialog as well:

Unhandled exception at line 1, column 1 in eval code
0x800a139e - JavaScript runtime error: Unhandled Error in Silverlight Application Object reference not set to an instance of an object.   at GlobalLabManager.Models.GLMAppointment.ValidateCategory()
   at GlobalLabManager.Models.GLMAppointment.ValidateAppointment()
   at GlobalLabManager.Models.GLMAppointment.get_Error()
   at Telerik.Windows.Controls.AppointmentDialogViewModel.IsAppointmentValid()
   at Telerik.Windows.Controls.AppointmentDialogViewModel.CanConfirm()
   at Telerik.Windows.Controls.SchedulerDialogViewModel.OnQueryConfirmCommand(Object sender, CanExecuteRoutedEventArgs e)
   at Telerik.Windows.Controls.CommandBinding.OnCanExecute(Object sender, CanExecuteRoutedEventArgs e)
   at Telerik.Windows.Controls.CommandManager.FindCommandBinding(CommandBindingCollection commandBindings, Object sender, RoutedEventArgs e, ICommand command, Boolean execute)
   at Telerik.Windows.Controls.CommandManager.FindCommandBinding(Object sender, RoutedEventArgs e, ICommand command, Boolean execute)
   at Telerik.Windows.Controls.CommandManager.OnCanExecute(Object sender, CanExecuteRoutedEventArgs e)
   at Telerik.Windows.Controls.CanExecuteRoutedEventArgs.InvokeEventHandler(Delegate genericHandler, Object target)
   at Telerik.Windows.RadRoutedEventArgs.InvokeHandler(Delegate handler, Object target)
   at Telerik.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RadRoutedEventArgs routedEventArgs)
   at Telerik.Windows.EventRoute.InvokeHandlersImpl(Object source, RadRoutedEventArgs args, Boolean raisedAgain)
   at Telerik.Windows.RadRoutedEventHelper.RaiseEvent(DependencyObject element, RadRoutedEventArgs args)
   at Telerik.Windows.Controls.RoutedCommand.CanExecuteImpl(Object parameter, UIElement target, Boolean& continueRouting)
   at Telerik.Windows.Controls.RoutedCommand.CanExecuteInternal(Object parameter, UIElement target, Boolean& continueRouting)
   at Telerik.Windows.Controls.RadButton.CanExecuteApply()
   at Telerik.Windows.Controls.RadButton.CanExecuteChanged(Object sender, EventArgs e)
   at Telerik.Windows.Controls.WeakEventHandlerManager.CallHandler(Object sender, EventHandler eventHandler)
   at Telerik.Windows.Controls.WeakEventHandlerManager.CallWeakReferenceHandlers(Object sender, List`1 handlers)
   at Telerik.Windows.Controls.CommandManager.<RaiseRequerySuggested>b__5()

Here's my custom appointment:

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using GlobalLabManager.Web;
using Telerik.Windows.Controls;
using Telerik.Windows.Controls.ScheduleView;
 
namespace GlobalLabManager.Models
{
    /// <summary>
    /// Implements a custom appointment which corresponds to a database Reservation record
    /// </summary>
    public partial class GLMAppointment : Telerik.Windows.Controls.ScheduleView.Appointment, IDataErrorInfo
    {
        public GLMAppointment()
        {
        }
 
        #region Fields
         
        private string _caseId;
        private ObservableCollection<Attendee> _availableAttendees;
        private ObservableCollection<Attendee> _assignedAttendees;
 
        private ObservableCollection<Device> _availableDevices;
        private ObservableCollection<Device> _assignedDevices;
         
        #endregion //Fields
         
        #region Properties
         
        public string Error
        {
            get
            {
                return this.ValidateAppointment();
            }
        }
 
        public string this[string columnName]
        {
            get
            {
                switch (columnName)
                {
                    case "Category":
                        return this.ValidateCategory();
                    case "Subject":
                        return this.ValidateSubject();
                    //case "CaseID":
                    //    return this.ValidateCaseID();
                    case "AvailableAttendees":
                        return this.ValidateAssignedAttendees();
                    case "AvailableDevices":
                        return this.ValidateAssignedDevices();
                }
                return null;
            }
        }
 
        public string CaseID
        {
            get
            {
                return this.Storage<GLMAppointment>()._caseId;
            }
            set
            {
                var storage = this.Storage<GLMAppointment>();
                if (storage._caseId != value)
                {
                    storage._caseId = value;
                    this.OnPropertyChanged(() => this.CaseID);
                }
            }
        }
         
        public ObservableCollection<Attendee> AvailableAttendees
        {
            get
            {
                return this.Storage<GLMAppointment>()._availableAttendees;
            }
            set
            {
                var storage = this.Storage<GLMAppointment>();
                if (storage._availableAttendees != value)
                {
                    storage._availableAttendees = value;
                    this.OnPropertyChanged(() => this.AvailableAttendees);
                }
            }
        }
 
        public ObservableCollection<Attendee> AssignedAttendees
        {
            get
            {
                return this.Storage<GLMAppointment>()._assignedAttendees;
            }
            set
            {
                var storage = this.Storage<GLMAppointment>();
                if (storage._assignedAttendees != value)
                {
                    storage._assignedAttendees = value;
                    this.OnPropertyChanged(() => this.AssignedAttendees);
                }
            }
        }
         
        public ObservableCollection<Device> AvailableDevices
        {
            get
            {
                return this.Storage<GLMAppointment>()._availableDevices;
            }
            set
            {
                var storage = this.Storage<GLMAppointment>();
                if (storage._availableDevices != value)
                {
                    storage._availableDevices = value;
                    this.OnPropertyChanged(() => this.AvailableDevices);
                }
            }
        }
         
        public ObservableCollection<Device> AssignedDevices
        {
            get
            {
                return this.Storage<GLMAppointment>()._assignedDevices;
            }
            set
            {
                var storage = this.Storage<GLMAppointment>();
                if (storage._assignedDevices != value)
                {
                    storage._assignedDevices = value;
                    this.OnPropertyChanged(() => this.AssignedDevices);
                }
            }
        }
 
        #endregion //Properties
 
        #region Methods
 
        public override IAppointment Copy()
        {
            IAppointment customAppt = new GLMAppointment();
            customAppt.CopyFrom(this);
            return customAppt;
        }
         
        public override void CopyFrom(IAppointment other)
        {
            GLMAppointment customAppt = other as GLMAppointment;
            if (customAppt != null)
            {
                this.CaseID = customAppt.CaseID;
                this.AvailableAttendees = customAppt.AvailableAttendees;
                this.AssignedAttendees = customAppt.AssignedAttendees;
                this.AvailableDevices = customAppt.AvailableDevices;
                this.AssignedDevices = customAppt.AssignedDevices;
            }
            base.CopyFrom(other);
        }
 
        protected override void OnPropertyChanged(string propertyName)
        {
            base.OnPropertyChanged(propertyName);
 
            if (propertyName == "Category" ||
                propertyName == "Subject" ||
                propertyName == "AssignedAttendees" ||
                propertyName == "AssignedDevices")
            {
                CommandManager.InvalidateRequerySuggested();
            }
        }
         
        private string ValidateAppointment()
        {
            string errorString = this.ValidateCategory();
            errorString += this.ValidateSubject();
            errorString += this.ValidateAssignedAttendees();
            errorString += this.ValidateAssignedDevices();
 
            return errorString;
        }
 
        private string ValidateCategory()
        {
            if (string.IsNullOrEmpty(this.Category.DisplayName))
            {
                return "Please select an appointment category!";
            }
            return null;
        }
 
        private string ValidateSubject()
        {
            if (string.IsNullOrEmpty(this.Subject))
            {
                return "The subject cannot be empty!";
            }
            return null;
        }
 
        //private string ValidateCaseID()
        //{
        //    if (this.Category.DisplayName == "Case-Related" && string.IsNullOrEmpty(this.CaseID))
        //    {
        //        return "Case ID is required for any case-related appointment!";
        //    }
        //    return null;
        //}
 
        private string ValidateAssignedAttendees()
        {
            if (this.AssignedAttendees == null)
            {
                return "At least one Attendee is required!";
            }
            return null;
        }
 
        private string ValidateAssignedDevices()
        {
            if (this.AssignedDevices == null)
            {
                return "At least one device is required!";
            }
            return null;
        }
         
        #endregion //Methods
    }
}
0
Yana
Telerik team
answered on 16 Sep 2013, 09:30 AM
Hello Art,

The custom appointment seems correct. I would ask you to send us a simple runnable project with the customized EditAppointmentDialog as well - in this way we will be able to test the exact scenario. Please open a support ticket and attach the project there.

Thanks in advance.

Regards,
Yana
Telerik
TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for SILVERLIGHT.
Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
Sign up for Free application insights >>
Tags
ScheduleView
Asked by
Art Kedzierski
Top achievements
Rank 2
Answers by
Yana
Telerik team
Art Kedzierski
Top achievements
Rank 2
Share this question
or