Day indicators based on data

16 posts, 0 answers
  1. Paul
    Paul avatar
    9 posts
    Member since:
    Dec 2011

    Posted 08 Dec 2011 Link to this post

    Hi Telerik

    In my calendar I need to indicate certain days to the user. I don't want to display appointment text but want to display an icon say to indicate birthdays, a different icon to indicate public holidays etc etc.

    From what I understand I could do this with special days but i believe that requires a template for each variation.

    Is there anyway I can change the background colour of the day or add an icon based on the data for a day? If so, are there any VB examples?

    Many thanks

    Paul
  2. Paul
    Paul avatar
    9 posts
    Member since:
    Dec 2011

    Posted 09 Dec 2011 Link to this post

    Anyone ?

    Pretty please :)
  3. DevCraft banner
  4. Brian Pautsch
    Brian Pautsch avatar
    15 posts
    Member since:
    Jun 2009

    Posted 12 Dec 2011 Link to this post

    Yeah, anyone? I'd think there would be a DataBound event or something we can intercept to FindControls and modify them.
  5. Todor
    Admin
    Todor avatar
    778 posts

    Posted 13 Dec 2011 Link to this post

    Hello Paul,

    Thank you for your question.

    You can use a data template with any content that you want including Images, TextBlocks, etc. for your special days. To define which days should be marked as "special" you should create your own class that inherits DataTemplateSelector and override the SelectTemplate method. There you can define your own custom logic for the dates that use the special template. If need to have more than one template, you will have to define a class for each one of them. An example in C# and in VB about special templates and about other features are available at our online documentation here.

    In general, for your special days you just create a DataTemplate and you can place any content inside: Images, TextBlocks, etc. For example, to change the background for a special day to "Red" and add an icon you need a data template like this:
    <DataTemplate>
        <Grid Background="Red">
            <Image Source="Images/1.png" Height="24" Width="24"/>
            <TextBlock Foreground="Black" Text="{Binding Text}"/>
        </Grid>
    </DataTemplate>

    I hope this helps. Do not hesitate to contact us if have any other questions.


    Regards,
    Todor
    the Telerik team

    Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

  6. Brian Pautsch
    Brian Pautsch avatar
    15 posts
    Member since:
    Jun 2009

    Posted 13 Dec 2011 Link to this post

    I completely understand what you're saying and I understand the code in the sample application, but I don't think this will work for me. Please read my scenario below and advise me on how to solve it. Unfortunately, this is very time sensitive and I need to resolve this today. If you cannot reply right away, I completely understand, but I'll then need to use the Resco controls which has an event that allows me to customize the day cell.

    In my application, customers can add appointments or tasks. When the calendar is displayed, I need to show up to 4 appts and up to 4 tasks per day. Row 1 is the appts and Row 2 is the tasks. The appts and tasks can also be color coded (e.g. red=urgent). There are 6 colors. So obviously I cannot have a template for each scenario...there would be hundreds of scenarios.

    To get it to almost work, I had to put Color:Type in the Subject when loading the control and then use the converter to parse the values. But the problem is that I cannot control which shape is colored and which is not dynamically.

    Any ideas? Thanks in advance.

    <DataTemplate x:Key="CustomDayTemplate">
        <Grid Margin="5">
            <StackPanel Margin="0,-2,0,0">
                <Grid Margin="0">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="Auto"/>
                    </Grid.ColumnDefinitions>
                    <Ellipse Fill="{Binding Path=DetailText, Converter={StaticResource CalBrushConverter}}" 
                            Width="8" Height="8" Grid.Row="0" Grid.Column="0" Margin="1" />
                    <Ellipse Fill="{Binding Path=DetailText, Converter={StaticResource CalBrushConverter}}" 
                            Width="8" Height="8" Grid.Row="0" Grid.Column="1" Margin="1" />
                    <Ellipse Fill="{Binding Path=DetailText, Converter={StaticResource CalBrushConverter}}" 
                            Width="8" Height="8" Grid.Row="0" Grid.Column="2" Margin="1" />
                    <Ellipse Fill="{Binding Path=DetailText, Converter={StaticResource CalBrushConverter}}" 
                            Width="8" Height="8" Grid.Row="0" Grid.Column="3" Margin="1" />
                    <Ellipse Fill="{Binding Path=DetailText, Converter={StaticResource CalBrushConverter}}" 
                            Width="8" Height="8" Grid.Row="0" Grid.Column="4" Margin="1" />
                    <Rectangle Fill="{Binding Path=DetailText, Converter={StaticResource CalBrushConverter}}" 
                            Width="8" Height="8" Grid.Row="1" Grid.Column="0" Margin="1" />
                    <Rectangle Fill="{Binding Path=DetailText, Converter={StaticResource CalBrushConverter}}" 
                            Width="8" Height="8" Grid.Row="1" Grid.Column="1" Margin="1" />
                    <Rectangle Fill="{Binding Path=DetailText, Converter={StaticResource CalBrushConverter}}" 
                            Width="8" Height="8" Grid.Row="1" Grid.Column="2" Margin="1" />
                    <Rectangle Fill="{Binding Path=DetailText, Converter={StaticResource CalBrushConverter}}" 
                            Width="8" Height="8" Grid.Row="1" Grid.Column="3" Margin="1" />
                    <Rectangle Fill="{Binding Path=DetailText, Converter={StaticResource CalBrushConverter}}" 
                            Width="8" Height="8" Grid.Row="1" Grid.Column="4" Margin="1" />
                </Grid>
            </StackPanel>
            <TextBlock Text="{Binding Text}" x:Name="TextPresenter" VerticalAlignment="Bottom" HorizontalAlignment="Left"/>
        </Grid>
    </DataTemplate>
    
  7. Brian Pautsch
    Brian Pautsch avatar
    15 posts
    Member since:
    Jun 2009

    Posted 13 Dec 2011 Link to this post

    I just had an idea...sort of hacky, but could solve it...unless you have a better idea.

    Bind the calendar with appointments where the subject is: Type:Location:Color
    For example, A:1:Red = Appt icon #1 color Red, or T:3:Blue = Task icon #3 Blue

    When the converter is called for each icon, inspect the DetailText for a match. If one is found, return the color.
    Only problem: How do I know which icon is requesting a color?
    If I give each shape a name, can I get that from one of the below parameters? I don't think so.

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    
  8. Brian Pautsch
    Brian Pautsch avatar
    15 posts
    Member since:
    Jun 2009

    Posted 13 Dec 2011 Link to this post

    I kept working at this and almost have the solution...so close. The only issue: When the converter is called, the DetailText keeps stringing together for different dates. When I get the 10 convert calls for the 1st date, I only see the data for that date...good! But when I get the 10 convert calls for the 2nd date, I see the data for the 1st AND 2nd date concatenated. I think you guys have a bug...it doesn't look like you're clearing that property for each date...or is that what you want it to do (I wouldn't think so...I can't see a practical use for that). My "solution" (not coded yet): use a private string variable to save the growing DetailText...when the length changes, "replace" the value passed in so all that;s left is the new date's data...and keep doing that for each call. Ugly, but will work. Thoughts?

    XAML:
    <DTviews:CalendarBrushConverter x:Key="CalBrushConverter"/>
    <DataTemplate x:Key="CustomDayTemplate">
        <Grid Margin="5">
            <StackPanel Margin="0,-2,0,0">
                <Grid Margin="0">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="Auto" />
                        <ColumnDefinition Width="Auto"/>
                    </Grid.ColumnDefinitions>
                    <Ellipse Fill="{Binding Path=DetailText, Converter={StaticResource CalBrushConverter}}" 
                            Width="8" Height="8" Grid.Row="0" Grid.Column="0" Margin="1" />
                    <Ellipse Fill="{Binding Path=DetailText, Converter={StaticResource CalBrushConverter}}" 
                            Width="8" Height="8" Grid.Row="0" Grid.Column="1" Margin="1" />
                    <Ellipse Fill="{Binding Path=DetailText, Converter={StaticResource CalBrushConverter}}" 
                            Width="8" Height="8" Grid.Row="0" Grid.Column="2" Margin="1" />
                    <Ellipse Fill="{Binding Path=DetailText, Converter={StaticResource CalBrushConverter}}" 
                            Width="8" Height="8" Grid.Row="0" Grid.Column="3" Margin="1" />
                    <Ellipse Fill="{Binding Path=DetailText, Converter={StaticResource CalBrushConverter}}" 
                            Width="8" Height="8" Grid.Row="0" Grid.Column="4" Margin="1" />
                    <Rectangle Fill="{Binding Path=DetailText, Converter={StaticResource CalBrushConverter}}" 
                            Width="8" Height="8" Grid.Row="1" Grid.Column="0" Margin="1" />
                    <Rectangle Fill="{Binding Path=DetailText, Converter={StaticResource CalBrushConverter}}" 
                            Width="8" Height="8" Grid.Row="1" Grid.Column="1" Margin="1" />
                    <Rectangle Fill="{Binding Path=DetailText, Converter={StaticResource CalBrushConverter}}" 
                            Width="8" Height="8" Grid.Row="1" Grid.Column="2" Margin="1" />
                    <Rectangle Fill="{Binding Path=DetailText, Converter={StaticResource CalBrushConverter}}" 
                            Width="8" Height="8" Grid.Row="1" Grid.Column="3" Margin="1" />
                    <Rectangle Fill="{Binding Path=DetailText, Converter={StaticResource CalBrushConverter}}" 
                            Width="8" Height="8" Grid.Row="1" Grid.Column="4" Margin="1" />
                </Grid>
            </StackPanel>
            <TextBlock Text="{Binding Text}" x:Name="TextPresenter" VerticalAlignment="Bottom" HorizontalAlignment="Left"/>
        </Grid>
    </DataTemplate>

    Load test date:
    tAppt.Add(new TAppointment() { StartDate = DateTime.Now, EndDate = DateTime.Now, Subject = "12/13/2011~Red~Blue~~~~Green~~~~" });
    tAppt.Add(new TAppointment() { StartDate = DateTime.Now, EndDate = DateTime.Now, Subject = "12/14/2011~Green~~~~~Green~Orange~~~" });
    

    Converter
    public CalendarBrushConverter()
    {
        this.brushes["NONE"] = new SolidColorBrush(Colors.Black);
        this.brushes["RED"] = new SolidColorBrush(Colors.Red);
        this.brushes["YELLOW"] = new SolidColorBrush(Colors.Yellow);
        this.brushes["PURPLE"] = new SolidColorBrush(Colors.Purple);
        this.brushes["BLUE"] = new SolidColorBrush(Colors.Blue);
        this.brushes["GREEN"] = new SolidColorBrush(Colors.Green);
        this.brushes["ORANGE"] = new SolidColorBrush(Colors.Orange);
    }
     
    
    DateTime lastDate = DateTime.Parse("1/1/1900");
    int shapeIndex = 0;
     
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        Brush result = null;
     
        //Get the value
        string color = value as string;
     
        //No value?
        if (color == null || color.Length == 0)
            color = string.Empty;
        else
        {
            //Remove last line break
            color = color.Remove(color.Length - 1);
     
            //Format: "Date~Color1~Color2~etc."
            if (color.Contains("~"))
            {
                //Get date
                DateTime currDate = DateTime.Parse(color.Substring(0, color.IndexOf("~")));
                        
                //New date?
                if (currDate != lastDate)
                {
                    lastDate = currDate;
                    shapeIndex = 0;
                }
                else
                    shapeIndex++;
     
                //Remove date from string
                color = color.Substring(color.IndexOf("~") + 1);
     
                //Get shape colors from string
                string[] colors = color.Split("~".ToCharArray());
     
                //Get color from array position
                color = colors[shapeIndex];
            }
        }
     
        //Try to find a match
        this.brushes.TryGetValue(color.ToUpper(), out result);
     
        //No match? Set to foreground color to hide
        if (result == null)
        {
            //result = Application.Current.Resources["PhoneForegroundBrush"] as Brush;
            this.brushes.TryGetValue("WHITE"out result);
        }
     
        return result;
    }
  9. Brian Pautsch
    Brian Pautsch avatar
    15 posts
    Member since:
    Jun 2009

    Posted 13 Dec 2011 Link to this post

    FYI: It works...but I think you guys still have a bug.
  10. Valentin.Stoychev
    Admin
    Valentin.Stoychev avatar
    2198 posts

    Posted 14 Dec 2011 Link to this post

    Hello Brian,

    Now that we have more details on your scenario, the best thing in your case to do is to bind directly to Appointments property (instead to DetailText) in your ItemTemplate.

    Then in the converter you can have a direct access to the appointment object (TAppointment). In your TAppointment class you can add any property that will be useful for you to choose the appropriate color.

    Please give it a try let us know how it goes.

    Greetings, Valentin.Stoychev
    the Telerik team

    Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

  11. Brian Pautsch
    Brian Pautsch avatar
    15 posts
    Member since:
    Jun 2009

    Posted 14 Dec 2011 Link to this post

    Thanks. That makes sense. I can update that now. But...is there any way to know which shape is calling the Converter? I'm assuming they are called in the sequence they are in the XAML, but that doesn't feel very safe. Can I pass a value in the parameters? Can I give the shapes names and somehow get that in the code behind?
  12. Valentin.Stoychev
    Admin
    Valentin.Stoychev avatar
    2198 posts

    Posted 14 Dec 2011 Link to this post

    Hi Brian Pautsch,

    Yes - you can add a parameter to the Binding, which will get passed to the converter. See here more info:
    http://www.silverlightshow.net/items/Tip-How-to-pass-a-parameter-to-a-value-converter.aspx

    All the best, Valentin.Stoychev
    the Telerik team

    Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

  13. Brian Pautsch
    Brian Pautsch avatar
    15 posts
    Member since:
    Jun 2009

    Posted 14 Dec 2011 Link to this post

    This is excellent guys. Thanks. When I get this done, I'll be sure to post my code to a blog so others can see the full solution.
  14. paul
    paul avatar
    16 posts
    Member since:
    Jan 2011

    Posted 03 Jan 2012 Link to this post

    Hi Brian

    Did you post your code anywhere?

  15. paul
    paul avatar
    16 posts
    Member since:
    Jan 2011

    Posted 03 Jan 2012 Link to this post

    Hi Valentin

    "Now that we have more details on your scenario, the best thing in your case to do is to bind directly to Appointments property (instead to DetailText) in your ItemTemplate."

    Please could you tell me how I can bind directly to appointments - sorry but I'm a little new to this :)
  16. Brian Pautsch
    Brian Pautsch avatar
    15 posts
    Member since:
    Jun 2009

    Posted 03 Jan 2012 Link to this post

    Sorry...didn't get around to it yet...here you go:
    Note: The code could be further optimized to send in the shape #...but this works well too.

    public class CalendarBrushConverter : IValueConverter
    {
        private Dictionary<string, Brush> brushes = new Dictionary<string, Brush>();

        public CalendarBrushConverter()
        {
            this.brushes["NONE"] = new SolidColorBrush(Colors.Black);
            this.brushes["BLACK"] = new SolidColorBrush(Colors.Black);
            this.brushes["RED"] = new SolidColorBrush(Colors.Red);
            this.brushes["YELLOW"] = new SolidColorBrush(Colors.Yellow);
            this.brushes["PURPLE"] = new SolidColorBrush(Colors.Purple);
            this.brushes["BLUE"] = new SolidColorBrush(Colors.Blue);
            this.brushes["GREEN"] = new SolidColorBrush(Colors.Green);
            this.brushes["ORANGE"] = new SolidColorBrush(Colors.Orange);
        }

        int shapeIndex = -1;

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            Brush result = null;

            //Default
            string color = "WHITE";

            TAppointment appt = null;

            //Anything passed in?
            if (value != null)
            {
                //Attempt to cast the object
                LinkedList<IAppointment> apptsTemp = (LinkedList<IAppointment>)value;

                //Any appointments in list?
                if (apptsTemp.Count > 0)
                {
                    //Get it
                    appt = (TAppointment)apptsTemp.FirstOrDefault();

                    //Appt sent in
                    if (appt != null)
                    {
                        //Bump up counter
                        shapeIndex++;

                        //Get color from array position
                        if (appt.ShapeColors[shapeIndex] != null)
                            color = appt.ShapeColors[shapeIndex];
                    }
                }
            }

            //Try to find a match
            this.brushes.TryGetValue(color.ToUpper(), out result);

            //No match? Set to foreground color to hide
            if (result == null)
                //result = Application.Current.Resources["PhoneForegroundBrush"] as Brush;
                this.brushes.TryGetValue("WHITE", out result);

            //Clean up
            if (shapeIndex == 9)
                shapeIndex = -1;

            return result;
        }

        protected virtual object GetValue(string value)
        {
            return value;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return value;
        }
    }
  17. paul
    paul avatar
    16 posts
    Member since:
    Jan 2011

    Posted 04 Jan 2012 Link to this post

    Thank you Brian - just what I needed
Back to Top
DevCraft banner