Special Days to Calendar Cell backcolor

15 posts, 3 answers
  1. DoomerDGR8
    DoomerDGR8 avatar
    133 posts
    Member since:
    Aug 2010

    Posted 01 Feb 2011 Link to this post

    Hi. I'm reading a set of dates from DB and based on the scenario, I've come-up with this:

    private void LoadLocumDiary() {
      foreach (Availability AvailabilityL in DbContext.Availabilities.Where(avail=> avail.LocumID == LocumID).OrderBy(date=>date.AvailableDate)) {
        RadCalendarDay sday = null;
     
        switch (AvailabilityL.AvailabilityStatusID) {
          case 1: //Available
          sday = new RadCalendarDay(AvailabilityL.AvailableDate) {
            Disabled = false,
            Selectable = true,
            ToolTip = AvailabilityL.AvailabilityStatus.Name
          };
          sday.TemplateItem.BackColor = Color.Green;
          break;
     
          case 2: //Unavailable
          sday = new RadCalendarDay(AvailabilityL.AvailableDate) {
            Disabled = false,
            Selectable = true,
            ToolTip = AvailabilityL.AvailabilityStatus.Name
          };
          sday.TemplateItem.BackColor = Color.Red;
          break;
     
          case 3: //On Job
          sday = new RadCalendarDay(AvailabilityL.AvailableDate) {
            Disabled = false,
            Selectable = true,
            ToolTip = AvailabilityL.AvailabilityStatus.Name
          };
          sday.TemplateItem.BackColor = Color.Goldenrod;
          break;
     
          default: break;
        }
     
        CalendarDiary.SpecialDays.Add(sday);
      }
     
     // CalendarDiary.InvalidateCalendar();
    }

    Now, I'm getting a null exception on sday.TemplateItem. What am I doing wrong. i need to set a tooltip and a back color on a day-cell.
  2. Answer
    Richard Slade
    Richard Slade avatar
    3000 posts
    Member since:
    May 2009

    Posted 01 Feb 2011 Link to this post

    Hi again Hassan,

    To change the back colour, you'll need to use the ElementRender event (much like the cell formatting event in the RadGridView) .
    The template item is null because it is a RadHostItem, and one is not contained in this instance.

    Have a look at this documentation which explains the important events in the radCalendar.

    Hope that helps
    Richard
  3. UI for WinForms is Visual Studio 2017 Ready
  4. DoomerDGR8
    DoomerDGR8 avatar
    133 posts
    Member since:
    Aug 2010

    Posted 02 Feb 2011 Link to this post

    Excellent answer. The links in the documentation are broken though. More importantly, if I subscribe the RenderElement event, how will I force the calendar to redraw or refresh so that it'll call the event again AFTER i made changes to the under-lying DB?
  5. Richard Slade
    Richard Slade avatar
    3000 posts
    Member since:
    May 2009

    Posted 02 Feb 2011 Link to this post

    Hi Hassan,

    I think in your situation you would just call RadCalendar1.Update(); though I'd need to see an exmaple to try this out. Give it a go, and if you find you need further help, then just let me know.
    Regards,
    Richard
  6. DoomerDGR8
    DoomerDGR8 avatar
    133 posts
    Member since:
    Aug 2010

    Posted 03 Feb 2011 Link to this post

    okay, the ElementRender event is fired just too many times. Even on selecting a day the UI hangs as it goes through my checks in the event. Can't i access the RadCalendarDay and the LightVisualElement some other way? My new strategy is to have my days customized whenever i want to manually.

    Here is what I'm trying to achieve:

    private void CalendarDiary_ElementRender(object sender, RenderElementEventArgs e) {
      if (e.Day.Date < DateTime.Now.Date) {
        return;
      }
     
      Cursor.Current = Cursors.WaitCursor;
     
      foreach (Availability AvailabilityL in ConcernedAvailabilities.Where(avail => avail.AvailableDate == e.Day.Date)) {
        switch (AvailabilityL.AvailabilityStatusID) {
          case 1: //Available
          e.Day.ToolTip = e.Element.ToolTipText = "Available";
          e.Element.BackColor = Color.FromArgb(177, 243, 177);
          e.Element.BackColor2 = Color.LimeGreen;
          e.Element.BackColor3 = Color.LimeGreen;
          e.Element.BackColor4 = Color.LimeGreen;
     
          e.Element.BorderColor = Color.Black;
          e.Element.BorderWidth = 1;
          break;
     
          case 2: //Unavailable
          e.Day.ToolTip = e.Element.ToolTipText = "Unavailable";
          e.Element.BackColor = Color.FromArgb(255, 218, 224);
          e.Element.BackColor2 = Color.LightPink;
          e.Element.BackColor3 = Color.LightPink;
          e.Element.BackColor4 = Color.LightPink;
     
          e.Element.BorderColor = Color.Black;
          e.Element.BorderWidth = 1;
          break;
     
          case 3: //On Job
          e.Day.ToolTip = e.Element.ToolTipText = "On Job";
          e.Element.BackColor = Color.FromArgb(248, 242, 198);
          e.Element.BackColor2 = Color.Khaki;
          e.Element.BackColor3 = Color.Khaki;
          e.Element.BackColor4 = Color.Khaki;          
     
          e.Element.BorderColor = Color.Black;
          e.Element.BorderWidth = 1;
          break;
     
          case 4: //Holiday
          e.Day.ToolTip = e.Element.ToolTipText = "On Holiday";
          e.Element.BackColor = Color.FromArgb(222, 239, 245);
          e.Element.BackColor2 = Color.LightBlue;
          e.Element.BackColor3 = Color.LightBlue;
          e.Element.BackColor4 = Color.LightBlue;
     
          e.Element.BorderColor = Color.Black;
          e.Element.BorderWidth = 1;
          break;
     
          default: break;
        }
      }
     
      Cursor.Current = Cursors.Default;
    }
  7. Richard Slade
    Richard Slade avatar
    3000 posts
    Member since:
    May 2009

    Posted 03 Feb 2011 Link to this post

    Hi,

    There is another way to loop over the cells in the calendar. You would need to do this each time the calendar changes month to check for special days and colour them .

    CalendarTableElement table = (CalendarTableElement)this.RadCalendar1.CalendarElement.CalendarVisualElement.Children[0].Children[1];
    foreach (CalendarCellElement cell in table.Children) {
        if (cell.SpecialDay) {
            switch (true) {
                case cell.Date == Today:
                    cell.BackColor = Color.Blue;
                    cell.NumberOfColors = 1;
                    break;
                case cell.Date == Today.AddDays(1):
                    cell.BackColor = Color.Green;
                    cell.NumberOfColors = 1;
                    break;
                case cell.Date == Today.AddDays(2):
                    cell.BackColor = Color.Pink;
                    cell.NumberOfColors = 1;
                    break;
            }
        }
    }

    Let me know if that helps
    Richard
  8. DoomerDGR8
    DoomerDGR8 avatar
    133 posts
    Member since:
    Aug 2010

    Posted 04 Feb 2011 Link to this post

    I still stuck with this...

    here is what I have so far:

    private void CustomPainting() {
      CalendarTableElement table = (CalendarTableElement)CalendarDiary.CalendarElement.CalendarVisualElement.Children[0].Children[1];
      var req = table.Children; //.Where(x => x is CalendarCellElement);
     
      foreach (CalendarCellElement cell in req) {
     
        if (ConcernedAvailabilities.Any(avail => avail.AvailableDate.Date == cell.Date.Date)) {
          Availability AvailabilityL = ConcernedAvailabilities.FirstOrDefault(avail => avail.AvailableDate.Date == cell.Date.Date);
     
          switch (AvailabilityL.AvailabilityStatusID) {
            case 1: //Available
            cell.ToolTipText = "Available";
            cell.BackColor = Color.FromArgb(177, 243, 177);
            cell.NumberOfColors = 1;
            cell.BorderColor = Color.Black;
            cell.BorderWidth = 1;
            break;
     
            case 2: //Unavailable
            cell.ToolTipText = "Unavailable";
            cell.BackColor = Color.FromArgb(255, 218, 224);
            cell.NumberOfColors = 1;
            cell.BorderColor = Color.Black;
            cell.BorderWidth = 1;
            break;
     
            case 4: //Holiday
            cell.ToolTipText = "Holiday";
            cell.BackColor = Color.FromArgb(222, 239, 245);
            cell.NumberOfColors = 1;
            cell.BorderColor = Color.Black;
            cell.BorderWidth = 1;
            break;
     
            case 3: //On Job
            cell.ToolTipText = "On Job";
            cell.BackColor = Color.FromArgb(248, 242, 198);
            cell.NumberOfColors = 1;
            cell.BorderColor = Color.Black;
            cell.BorderWidth = 1;
            break;
     
            default: break;
          }
        }
      }
     
    }

    Now, thetable.Children returns four items and they are the four multiview calendars I'm using... what can I do now?
  9. Answer
    Richard Slade
    Richard Slade avatar
    3000 posts
    Member since:
    May 2009

    Posted 04 Feb 2011 Link to this post

    Hello Hassan,

    If I understand you correctly, then you'd need to create an outer loop, to loop over the 4 calendars that are contained within the table.Children.
    Hope that helps
    Richard
  10. DoomerDGR8
    DoomerDGR8 avatar
    133 posts
    Member since:
    Aug 2010

    Posted 04 Feb 2011 Link to this post

    Did that bit.

    The outer for-each is like this now:

    private void CustomPainting() {
      CalendarTableElement table = (CalendarTableElement)CalendarDiary.CalendarElement.CalendarVisualElement.Children[0].Children[1];
      var req = table.Children.Where(x => x is MonthViewElement);
     
      foreach (MonthViewElement cell in req) {
     
        if (ConcernedAvailabilities.Any(avail => avail.AvailableDate.Date == cell.Date.Date)) {
          Availability AvailabilityL = ConcernedAvailabilities.FirstOrDefault(avail => avail.AvailableDate.Date == cell.Date.Date);
     
          switch (AvailabilityL.AvailabilityStatusID) {
            case 1: //Available
            cell.ToolTipText = "Available";
            cell.BackColor = Color.FromArgb(177, 243, 177);
            cell.NumberOfColors = 1;
            cell.BorderColor = Color.Black;
            cell.BorderWidth = 1;
            break;
     
            case 2: //Unavailable
            cell.ToolTipText = "Unavailable";
            cell.BackColor = Color.FromArgb(255, 218, 224);
            cell.NumberOfColors = 1;
            cell.BorderColor = Color.Black;
            cell.BorderWidth = 1;
            break;
     
            case 4: //Holiday
            cell.ToolTipText = "Holiday";
            cell.BackColor = Color.FromArgb(222, 239, 245);
            cell.NumberOfColors = 1;
            cell.BorderColor = Color.Black;
            cell.BorderWidth = 1;
            break;
     
            case 3: //On Job
            cell.ToolTipText = "On Job";
            cell.BackColor = Color.FromArgb(248, 242, 198);
            cell.NumberOfColors = 1;
            cell.BorderColor = Color.Black;
            cell.BorderWidth = 1;
            break;
     
            default: break;
          }
        }
      }
     
    }

    what will be the inner loop like?
  11. DoomerDGR8
    DoomerDGR8 avatar
    133 posts
    Member since:
    Aug 2010

    Posted 04 Feb 2011 Link to this post

    Okay, I figured the outer and the inner loops as follows:

    private void CustomPainting() {
      Cursor.Current = Cursors.WaitCursor;
     
      foreach (MonthViewElement currentMonthViewElement  in CalendarDiary.RootElement.Children[0].Children[0].Children[2].Children[0].Children[1].Children) {
        CalendarTableElement table = (CalendarTableElement)currentMonthViewElement.Children[0].Children[1];
     
        foreach (CalendarCellElement cell in table.Children) {
          if (ConcernedAvailabilities.Any(avail => avail.AvailableDate.Date == cell.Date.Date)) {
            Availability AvailabilityL = ConcernedAvailabilities.FirstOrDefault(avail => avail.AvailableDate.Date == cell.Date.Date);
     
            switch (AvailabilityL.AvailabilityStatusID) {
              case 1: //Available
              cell.ToolTipText = "Available";
              cell.BackColor = Color.FromArgb(177, 243, 177);
              cell.NumberOfColors = 1;
              cell.BorderColor = Color.Black;
              cell.BorderWidth = 1;
              break;
     
              case 2: //Unavailable
              cell.ToolTipText = "Unavailable";
              cell.BackColor = Color.FromArgb(255, 218, 224);
              cell.NumberOfColors = 1;
              cell.BorderColor = Color.Black;
              cell.BorderWidth = 1;
              break;
     
              case 4: //Holiday
              cell.ToolTipText = "Holiday";
              cell.BackColor = Color.FromArgb(222, 239, 245);
              cell.NumberOfColors = 1;
              cell.BorderColor = Color.Black;
              cell.BorderWidth = 1;
              break;
     
              case 3: //On Job
              cell.ToolTipText = "On Job";
              cell.BackColor = Color.FromArgb(248, 242, 198);
              cell.NumberOfColors = 1;
              cell.BorderColor = Color.Black;
              cell.BorderWidth = 1;
              break;
     
              default:
                break;
            }
     
            cell.Invalidate();
          }
        }
     
      }
     
      Cursor.Current = Cursors.Default;
    }

    Problem is, all cells are getting painted. The whole calendar is painted. Maybe i need to implement if-else and in the else, I need to re-set a cell's formatiing. How do I re-set to theme's default?
  12. Answer
    Richard Slade
    Richard Slade avatar
    3000 posts
    Member since:
    May 2009

    Posted 04 Feb 2011 Link to this post

    Hi Hassan,

    To reset a value, an exmaple (for back color) would be as followis

    cell.ResetValue(LightVisualElement.BackColorProperty)

    Hope that helps
    Richard
  13. DoomerDGR8
    DoomerDGR8 avatar
    133 posts
    Member since:
    Aug 2010

    Posted 04 Feb 2011 Link to this post

    One last thing, handling the else part leaves the whole calender in a washed-out state as all rowheaders and column headers are also a CalendarCellElement. How can I find the DayCellElement only (if there is such a thing)?
  14. Richard Slade
    Richard Slade avatar
    3000 posts
    Member since:
    May 2009

    Posted 04 Feb 2011 Link to this post

    Hi Hassan,

    As you are looping though, you could just inspect the cell text to see if it's an integer (a day) as the headers will be M,T,W,T,F etc...
    E.g.

    Dim result As Integer = -1
    If Integer.TryParse(cell.Text, result) Then
        Debug.WriteLine(result) ' It's a day cell
    End If

    Hope that helps
    Richard
  15. DoomerDGR8
    DoomerDGR8 avatar
    133 posts
    Member since:
    Aug 2010

    Posted 04 Feb 2011 Link to this post

    Well, I actually started with that but after much brain hammering, I found a very simple and descent solution:

    Final Code:

    private void CustomPainting() {
      Cursor.Current = Cursors.WaitCursor;
     
      foreach (MonthViewElement currentMonthViewElement  in CalendarDiary.RootElement.Children[0].Children[0].Children[2].Children[0].Children[1].Children) {
        var CalendarCellElements = ((CalendarTableElement)currentMonthViewElement.Children[0].Children[1]).Children.OfType < CalendarCellElement>();
        //var CalendarCellElements1 = CalendarCellElements.Where(x => x.Tag != null && x.Tag.ToString() == "xCell");
         
        foreach (CalendarCellElement cell in CalendarCellElements.Where(x=> x.Column>0 && x.Row>0)) {
           
          if (ConcernedAvailabilities.Any(avail => avail.AvailableDate.Date == cell.Date.Date)) {
            Availability AvailabilityL = ConcernedAvailabilities.FirstOrDefault(avail => avail.AvailableDate.Date == cell.Date.Date);
     
            switch (AvailabilityL.AvailabilityStatusID) {
              case 1: //Available
              cell.ToolTipText = "Available";
              cell.BackColor = Color.FromArgb(177, 243, 177);
              cell.NumberOfColors = 1;
              //cell.BorderColor = Color.Black;
              //cell.BorderWidth = 1;
              break;
     
              case 2: //Unavailable
              cell.ToolTipText = "Unavailable";
              cell.BackColor = Color.FromArgb(255, 218, 224);
              cell.NumberOfColors = 1;
              //cell.BorderColor = Color.Black;
              //cell.BorderWidth = 1;
              break;
     
              case 4: //Holiday
              cell.ToolTipText = "Holiday";
              cell.BackColor = Color.FromArgb(222, 239, 245);
              cell.NumberOfColors = 1;
              //cell.BorderColor = Color.Black;
              //cell.BorderWidth = 1;
              break;
     
              case 3: //On Job
              cell.ToolTipText = "On Job";
              cell.BackColor = Color.FromArgb(248, 242, 198);
              cell.NumberOfColors = 1;
              //cell.BorderColor = Color.Black;
              //cell.BorderWidth = 1;
              break;
     
              default:
              break;
            }
     
            cell.Invalidate();
     
          } else {           
            cell.ToolTipText = String.Empty;
            //cell.ResetValue(LightVisualElement.BorderWidthProperty);
            //cell.ResetValue(LightVisualElement.BorderColorProperty);
            cell.ResetValue(LightVisualElement.BackColorProperty);
            cell.ResetValue(LightVisualElement.NumberOfColorsProperty);
                         
            cell.Invalidate();
     
          }
        }
     
      }
     
      CalendarDiary.InvalidateCalendar();
     
      Cursor.Current = Cursors.Default;
    }

    Looking with Row and Column > 0 puts us in the actual day cells.
  16. Richard Slade
    Richard Slade avatar
    3000 posts
    Member since:
    May 2009

    Posted 04 Feb 2011 Link to this post

    Glad you have it all sorted.
    All the best
    Richard
Back to Top
UI for WinForms is Visual Studio 2017 Ready