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

Styling the TimeLine view

5 Answers 347 Views
ScheduleView
This is a migrated thread and some comments may be shown as answers.
Peter
Top achievements
Rank 1
Peter asked on 12 Aug 2014, 09:02 AM
I'm currently working on getting the ScheduleView to act like a nice Gantt chart for a project. In essence, what we require is a chart that displays A series of Gantt-lines for items to show reservations in a TimeLine view.

Currently, we're having issues getting the styling to work correctly and would like to know what styles to change to get the following to work:

* Kill the hours/minutes line. We want it gone entirely.
* Format date be two lines with weekdays as names below the date 
* Replace the resources with a custom view (we use MVVM of course) To have a lot more information display, including an image per item.
* Have the option for coloring each booking-entry according to an enum on the object (ie red for bookings, yellow for maintenances, green for unconfirmed bookings etc)

So far we've managed to edit the resources for the RadScheduleView to hide the timeLine button entirely when the title is null, but trying various suggestions and test-projects found on these forums for the rest has, so far, not helped with the other stuff. An example is the hours/minutes line that looks odd. I found a reply her telling me to set the TimeRulerItemStyleSelector to null and have an empty style to replace it (height + width set to 0, visibility collapsed) but, as the attached image shows, this didn't quite do the trick.

Any and all help is appreciated :)

5 Answers, 1 is accepted

Sort by
0
Yana
Telerik team
answered on 14 Aug 2014, 12:16 PM
Hello Peter,

For the first two requirements you should customize the TimeRulerItemStyleSelector for hiding the second row and TimeRulerItemTemplateSelector - for customizing the template of the first row in the TimeRuler.
I have attached a sample demonstrated the needed approach, please note that I've used Implicit Styles, so you should reference the NoXaml assemblies.

As to the other two questions:
  • You should create a custom GroupHeaderContentTemplateSelector as explained in our Templating the GroupHeaders topic in order to customize the look of the Resources headers.
  • RadScheduleView provides a way to apply different Style to the appointments through its AppointmentStyleSelector property, please check the Appointment Style help topic for more details on the approach.

Hope this will be helpful.

Regards,
Yana
Telerik
 
Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
 
0
Peter
Top achievements
Rank 1
answered on 14 Aug 2014, 01:49 PM
Thanks!

I've fought long and hard and got much of this working. However, I'm not stuck at an impasse that has kept me from getting the last things working (and confirming that this is, indeed, the product we wish to buy):

When adding Appointments they all clump together under one item. This is insanely annoying and by all logic in the code, they shouldn't.

My XAML binds to a GanttItem which is an extension of a Resource that contains a viewmodel. This all works flawlessly and allows us to edit the view as we please. Yay! 

If I load the RadScheduleView with one ID and build up a chart, it works. However, adding more causes an odd issue: ALL the appointments bind to the same Group rather than the groups I insert them into. I have posted the .CS file for the viewmodel (we use MVVM) for your perusal at the bottom of this post. 

Explanations of various function calls:

OnPresented is called once the window opens.
ServiceFactory.Get<ContractsService>().Getbookings grabs all bookings that we need to create appointments from.
Enums.TTObjectType is an enum with values Employee or ProductITem. It is used to distinguish the two and the GanttItem view we inject is colored to signify the object type.
AddGanttTasksFromBookings is the meat and potatoes of the viewmodel, attempting to take each ID and create a GanttResource (for the Groupheader) and add appointmnts to it. This is where things go wonkey, and deposite each Resource being creating and having its own appointments attached to it, it instead attaches all the appointments to the first resource for some reason. 

If you can help us solve this problem, that would be amazingly helpful :)

**************************************************************GanttChartBookingOverviewViewModel.CS**********************************************************

public class GanttChartBookingOverviewViewModel : ContentViewModel
    {
        private List<Booking> bookings;

        public Dictionary<Guid, Enums.TTObjectType> BookableObjectIDs { get; set; }

        public ObservableCollection<Appointment> Appointments { get; set; }

        public ResourceTypeCollection ResourceTypes { get; set; }

        public GroupDescriptionCollection GroupSource { get; set; }

        public GanttChartBookingOverviewViewModel()
        {
            this.Appointments = new ObservableCollection<Appointment>();
            this.bookings = new List<Booking>();
            this.BookableObjectIDs = new Dictionary<Guid, Enums.TTObjectType>();
            this.ResourceTypes = new ResourceTypeCollection();

            // Handle the groupsource. This adds the cardviews to the sidebar
            this.GroupSource = new GroupDescriptionCollection
                                    {
                                        new ResourceGroupDescription
                                        {
                                            ResourceType = "ProductItem"
                                        },
                                        new ResourceGroupDescription
                                        {
                                            ResourceType = "Employee"
                                        }
                                    };
        }

        public GanttChartBookingOverviewViewModel(IEnumerable<Guid> objectIDs, Enums.TTObjectType typeIn)
            : this()
        {
            objectIDs = new List<Guid>
                        {
                            new Guid("902EA17E-E9F7-4067-B793-AF3583B34DA3"),
                            new Guid("055DE60A-9933-4F51-9791-94007AD15271"),
                            new Guid("2690A715-DAD7-4B20-918F-36EB6CA4A578")
                        };

            foreach (var id in objectIDs)
            {
                this.BookableObjectIDs.Add(id, typeIn);
            }
        }

        public override void OnPresented()
        {
            this.GetPresenter().StartWaiting("Henter data...");
            Task.Factory.StartNew(
                () =>
                {
                    // Get all the bookings
                    this.bookings = ServiceFactory.Get<ContractsService>().Getbookings(this.BookableObjectIDs.Keys.ToList());
                }).ContinueWith(
                    t =>
                    {
                        this.AddGanttTasksFromBookings();
                        this.GetPresenter().FinishedWaiting();
                    },
                    TaskScheduler.FromCurrentSynchronizationContext());
        }

        /// <summary>
        /// Adds another item to the chart
        /// </summary>
        /// <param name="objectIDs">IDs of objects to add bookings for</param>
        /// <param name="typeIn">Type of object</param>
        public void AddGanttTasksToChart(IEnumerable<Guid> objectIDs, Enums.TTObjectType typeIn)
        {
            //// Add the new ID's and types to the dictionary
            //foreach (var id in objectIDs)
            //{
            //    if (this.BookableObjectIDs.ContainsKey(id))
            //    {
            //        break;
            //    }

            //    this.BookableObjectIDs.Add(id, typeIn);
            //}

            //this.GetPresenter().StartWaiting("Opdaterer data...");
            //Task.Factory.StartNew(
            //    () =>
            //    {
            //        // Get all the bookings
            //        this.bookings = ServiceFactory.Get<ContractsService>().Getbookings(BookableObjectIDs.Keys.ToList());
            //    }).ContinueWith(
            //        t =>
            //        {
            //            this.AddGanttTasksFromBookings();
            //            this.GetPresenter().FinishedWaiting();
            //        },
            //        TaskScheduler.FromCurrentSynchronizationContext());
        }

        /// <summary>
        /// Adds appointments to the RadScheduleView based on appointments
        /// </summary>
        private void AddGanttTasksFromBookings()
        {
            // Create the ResourceTypes
            var productResourceType = new ResourceType("ProductItem");
            var employeeResourceType = new ResourceType("Employee");

            // Create a dictionary for bookings, where the key is the ID of the object being referred to
            var bookingDictionary = bookings.GroupBy(x => x.ItemID).ToDictionary(x => x.Key, x => x.ToList());

            // Add our resources
            foreach (var bookableObjectID in BookableObjectIDs)
            {
                var resource = new GanttResource { ViewModel = new GanttItemViewModel(bookableObjectID.Key, bookableObjectID.Value) };

                // Add appointments from bookings
                var bookingsForItem = bookingDictionary.SingleOrDefault(x => x.Key == bookableObjectID.Key);

                // Handle 0 bookings to ensure item is displayed
                if (bookingsForItem.Value == null || bookingsForItem.Value.Count < 1)
                {
                    bookingsForItem = new KeyValuePair<Guid, List<Booking>>(
                        bookableObjectID.Key,
                        new List<Booking>
                        {
                            new Booking
                            {
                                ExpectedEndDate = DateTime.Now.AddYears(-5),
                                StartDateTime = DateTime.Now.AddYears(-5)
                            }
                        });
                }

                foreach (var singleBooking in bookingsForItem.Value)
                {
                    if (singleBooking.ExpectedEndDate == null)
                    {
                        singleBooking.ExpectedEndDate = DateTime.Now.AddYears(1);
                    }

                    var appointment = new Appointment
                                      {
                                          Subject = "Booking",
                                          Start = singleBooking.StartDateTime,
                                          End = singleBooking.ExpectedEndDate.Value
                                      };

                    appointment.Resources.Add(resource);

                    this.Appointments.Add(appointment);
                }

                if (bookableObjectID.Value == Enums.TTObjectType.ProductItem)
                {
                    productResourceType.Resources.Add(resource);
                }

                if (bookableObjectID.Value == Enums.TTObjectType.Employee)
                {
                    employeeResourceType.Resources.Add(resource);
                }

            }

            this.ResourceTypes.Add(productResourceType);
            this.ResourceTypes.Add(employeeResourceType);
        }
    }








0
Yana
Telerik team
answered on 18 Aug 2014, 10:26 AM
Hi Peter,

I am afraid that the provided information is not enough for us to tell what could cause such an issue. Do you mean that the problem occurs when you have two RadScheduleView instances? Can you try to isolate it in a simple project ( without the database, only with static data) and send it to us, so we to be able to test the exact scenario?

Regards,
Yana
Telerik
 
Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
 
0
Peter
Top achievements
Rank 1
answered on 27 Aug 2014, 01:44 PM
We eventually found the issue by determining each appointment requires a string-value to attach it properly to a resource.

We now have it all working and are looking at styling. Most is self-explanatory, however, I'm having issues locating two key pieces to style the view how we want, more specifically:

Main bar (with forward/backward buttons etc).  Where do we hook into to change the styling (currently worried about background color)

Background of the window- we managed to locate the styling in the ScheduleView.xaml resource dictionary. We wish to be able to color certain days a different color (ie weekends and holidays) Do you have any logic already made for this or do we need to create our own?

Thanks for your time!
0
Yana
Telerik team
answered on 29 Aug 2014, 10:12 AM
Hello Peter,

As to the first requirement - you should extract the ControlTemplate of the ScheduleView ( as explained in Editing Control Templates topic) and find in it the Border with NavigationHeader name  - you could change its style there,

For the second requirement I would suggest that you use SpecialSlots and SpecialSlotsStyleSelector in order to apply different Styles to specific slots. For more details please check the Special and ReadOnly slots topic in our documentation.

Hope this will be helpful.

Regards,
Yana
Telerik
 
Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
 
Tags
ScheduleView
Asked by
Peter
Top achievements
Rank 1
Answers by
Yana
Telerik team
Peter
Top achievements
Rank 1
Share this question
or