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

Day indicators based on data

15 Answers 101 Views
Calendar
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
Paul
Top achievements
Rank 1
Paul asked on 08 Dec 2011, 03:56 PM
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

15 Answers, 1 is accepted

Sort by
0
Paul
Top achievements
Rank 1
answered on 09 Dec 2011, 12:08 PM
Anyone ?

Pretty please :)
0
Chris Pautsch
Top achievements
Rank 1
answered on 13 Dec 2011, 04:33 AM
Yeah, anyone? I'd think there would be a DataBound event or something we can intercept to FindControls and modify them.
0
Todor
Telerik team
answered on 13 Dec 2011, 07:35 AM
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 >>

0
Chris Pautsch
Top achievements
Rank 1
answered on 13 Dec 2011, 03:39 PM
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>
0
Chris Pautsch
Top achievements
Rank 1
answered on 13 Dec 2011, 03:49 PM
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)
0
Chris Pautsch
Top achievements
Rank 1
answered on 13 Dec 2011, 06:32 PM
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;
}
0
Chris Pautsch
Top achievements
Rank 1
answered on 13 Dec 2011, 06:49 PM
FYI: It works...but I think you guys still have a bug.
0
Valentin.Stoychev
Telerik team
answered on 14 Dec 2011, 08:35 AM
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 >>

0
Chris Pautsch
Top achievements
Rank 1
answered on 14 Dec 2011, 04:45 PM
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?
0
Valentin.Stoychev
Telerik team
answered on 14 Dec 2011, 09:00 PM
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 >>

0
Chris Pautsch
Top achievements
Rank 1
answered on 14 Dec 2011, 10:59 PM
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.
0
paul
Top achievements
Rank 1
answered on 03 Jan 2012, 08:36 PM

Hi Brian

Did you post your code anywhere?

0
paul
Top achievements
Rank 1
answered on 03 Jan 2012, 08:49 PM
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 :)
0
Chris Pautsch
Top achievements
Rank 1
answered on 03 Jan 2012, 08:59 PM
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;
    }
}
0
paul
Top achievements
Rank 1
answered on 04 Jan 2012, 02:35 PM
Thank you Brian - just what I needed
Tags
Calendar
Asked by
Paul
Top achievements
Rank 1
Answers by
Paul
Top achievements
Rank 1
Chris Pautsch
Top achievements
Rank 1
Todor
Telerik team
Valentin.Stoychev
Telerik team
paul
Top achievements
Rank 1
Share this question
or