Refactoring telerik RadScheduleView ReadOnly example to attached behavior

27 באוגוסט 2011

אין תגובות


Refactoring to attached behavior


At the project I’m currently working on, I had to integrate Telerik’s RadScheduleView in a WPF application that uses Caliburn Micro as MVVM framework. The RadScheduleView is a time management  component, however, we needed it only for presentation – thus we had to make it a read only control.


The control itself does not expose an “IsReadOnly” property, so I found this post at Telerik’s forums. It includes a code sample that shows how to do it, but it does not conform nicely to the M-V-VM Pattern – So I had to refactor it to Attached Behavior.


The Problem: Code in Code-Behind


The demo project places the event handling code of 4 events (AppointmentCreating, AppointmentDeleting, AppointmentEditing and ShowDialog) in the code behind the MainWindow (MainWindow.xaml.cs file).


Since we’re using Caliburn, we did not want to break pattern and add code to our view’s .xaml.cs file. This way, our code behind will remain slim and clean.


The Solution: Attached Behaviors


Attached Behaviors enable changing of behavior of WPF controls in a declarative manner, with no unwanted code residue in the view.


The magic uses Attached Properties: Since attached properties are dependency properties, code can register to a property change event. The event handler then modifies the control’s properties and events to have the required functionality.


Result (Code):


(Code is provided as-is.)


 using  System;
 using  System.Windows;
 using  Telerik.Windows.Controls;
 
 namespace  Wpf_RadScheduleView
 {
     public  static  class  ReadOnlyBehavior 
     {
         private  const  string  INVALID_TYPE_ERROR_MESSAGE = 
             "This attached behavior can only be aplied on RadScheduleView controls." ;
 
 
         public  static  bool  GetIsReadOnly(DependencyObject  obj)
         {
             return  (bool )obj.GetValue(IsReadOnlyProperty);
         }
 
         public  static  void  SetIsReadOnly(DependencyObject  obj, bool  value)
         {
             obj.SetValue(IsReadOnlyProperty, value);
         }
 
         public  static  readonly  DependencyProperty  IsReadOnlyProperty =
             DependencyProperty .RegisterAttached("IsReadOnly" , 
                                                 typeof (bool ), 
                                                 typeof (ReadOnlyBehavior ), 
                                                 new  UIPropertyMetadata (false , 
                                                                        IsReadOnlyChanged));
 
         private  static  void  IsReadOnlyChanged(DependencyObject  d, 
                                               DependencyPropertyChangedEventArgs  e)
         {
             if  (d == null )
             {
                 throw  new  ArgumentNullException ("d" );
             }
             var  scheduleView = d as  RadScheduleView ;
             if  (scheduleView == null )
             {
                 throw  new  ArgumentException (INVALID_TYPE_ERROR_MESSAGE, "d" );
             }
 
             var  shouldBeReadOnly = (bool )e.NewValue;
             if  (shouldBeReadOnly)
             {
                 RegisterInteractionEventHandlers(scheduleView);
             }
             else 
             {
                 var  shouldCleanup = (bool )e.OldValue;
                 if  (shouldCleanup)
                 {
                     UnregisterInteractionEventHandlers(scheduleView);
                 }
             }
         }
 
         private  static  void  UnregisterInteractionEventHandlers(RadScheduleView  scheduleView)
         {
             scheduleView.AppointmentCreating -= CancelAppointmentCreating;
             scheduleView.AppointmentDeleting -= CancelAppointmentDeleting;
             scheduleView.AppointmentEditing -= CancelAppointmentEditing;
         }
 
         private  static  void  RegisterInteractionEventHandlers(RadScheduleView  scheduleView)
         {
             scheduleView.AppointmentCreating += CancelAppointmentCreating;
             scheduleView.AppointmentDeleting += CancelAppointmentDeleting;
             scheduleView.AppointmentEditing += CancelAppointmentEditing;
         }
 
         private  static  void  CancelAppointmentEditing(object  sender, 
                                                      AppointmentEditingEventArgs  e)
         {
             e.Cancel = true ;
         }
 
         private  static  void  CancelAppointmentDeleting(object  sender, 
                                                       AppointmentDeletingEventArgs  e)
         {
             e.Cancel = true ;
         }
 
         private  static  void  CancelAppointmentCreating(object  sender, 
                                                       AppointmentCreatingEventArgs  e)
         {
             e.Cancel = true ;
         }
     }
 }
 

Now, this behavior can be applied in XAML like this:


 <telerik:RadScheduleView x:Name="schedule"  
          AppointmentsSource="{Binding Appointments}" 
          ResourceTypesSource="{Binding ResourcesTypes}" 
          local:ReadOnlyBehavior.IsReadOnly="True" > 
     <!– … –> 
 
 

Last Step


In order for the project to compile, I have to change the ReadOnlyDragAndDropBehavior’s base class inherit from ScheduleViewDragDropBehavior and not from DefaultDragDropBehavior, as it is obsolete.


Next Possible Steps


It is also possible to turn this Attached Behavior to a System.Windows.Interactivity.Behavior, but we thought it would be overshooting.


Another option to include the ReadOnlyDragAndDropBehavior in the attached behavior, but since I knew we’re not going to set the behavior to re-enable editing, and the assignment is still done in xaml, I did not really care about where to set it.


Update: I’ve noticed that Telerik also have a RadScheduler control, and that Scheduler has read only capabilities – so if it’s possible, consider using that control instead of the RadScheduleView.


ReUpdate: It turnes out that the RadScheduleView is the new control of the two.. If you need to migrate, Telerik has a help post about it.


Enjoy, and happy coding!

הוסף תגובה
facebook linkedin twitter email

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *