Customizable DataTemplate

Mar 15, 2012 at 1:52 PM

Hi Sergey, I would like to say great job on the Calendar Control for Windows Phone 7, it really helps me on my current project,

But I find a little difficulty on modifying it, I follow your guides to customize its Style, and it works, but it wasn't enough for me, I need to add other item besides the ItemDate and DayNumber property, as I follow your other guides, I found that I can do it by creating a class which inherits ISupportCalendarItem, and put it on an ObservableCollection which then binded with DatesSource property of the Calendar. On your guides, you show how to use it on a converter which then changes the Background Color, but I need more data which can be binded into the Calendar, so I add an ISupportCalendarItem Property on CalendarItem Class

        public ISupportCalendarItem SupportItem
        {
            get { return (ISupportCalendarItem) GetValue(SupportItemProperty); }
            set { SetValue(SupportItemProperty, value); }
        }

        internal static readonly DependencyProperty SupportItemProperty =
            DependencyProperty.Register("SupportItem", typeof(ISupportCalendarItem), typeof(CalendarItem), new PropertyMetadata(null));

And then add additional function on Calendar class

        private void RefreshInfo()
        {
            if (_itemsGrid != null)
            {
                for (int rowCount = 1; rowCount <= RowCount; rowCount++)
                {
                    for (var columnCount = 1; columnCount < ColumnCount; columnCount++)
                    {
                        var item = (CalendarItem)(from oneChild in _itemsGrid.Children
                                                  where oneChild is CalendarItem &&
                                                  ((CalendarItem)oneChild).Tag.ToString() == string.Concat(rowCount.ToString(), ":", columnCount.ToString())
                                                  select oneChild).First();
                        if (item != null)
                        {
                            item.SupportItem = null;
                            foreach (ISupportCalendarItem supportitem in DatesSource)
                            {
                                if (supportitem.CalendarItemDate.Date == item.ItemDate.Date)
                                {
                                    item.SupportItem = supportitem;
                                }
                            }

                        }
                    }
                }
            }
        }

Which is called from within the Refresh functions. by doing that, it allows me to bind additional information into the template, such as below, and customize my calendar more freely

<Style TargetType="wpcontrol:CalendarItem">
                                <Setter Property="Background" Value="Transparent"/>
                                <Setter Property="Template">
                                    <Setter.Value>
                                        <ControlTemplate  TargetType="wpcontrol:CalendarItem">
                                            <Grid x:Name="OuterGrid" HorizontalAlignment="Stretch"
                                              VerticalAlignment="Stretch">
                                                <Border
                                                BorderThickness="1"
                                                HorizontalAlignment="Stretch"
                                                VerticalAlignment="Stretch"
                                                BorderBrush="{StaticResource PhoneForegroundBrush}">
                                                    <Grid Height="90" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
                                                        <Grid.RowDefinitions>
                                                            <RowDefinition/>
                                                            <RowDefinition/>
                                                        </Grid.RowDefinitions>
                                                        <Grid.ColumnDefinitions>
                                                            <ColumnDefinition/>
                                                            <ColumnDefinition/>
                                                        </Grid.ColumnDefinitions>
                                                        <Rectangle Grid.RowSpan="2" Grid.ColumnSpan="3"
                                                         x:Name="BackgroundRectangle" Fill="{TemplateBinding Background}" />
                                                        <TextBlock Grid.ColumnSpan="3" x:Name="DayNumberBlock"
                                                            Text="{Binding Path=DayNumber,RelativeSource={RelativeSource TemplatedParent}}"
                                                            Foreground="{TemplateBinding Foreground}"
                                                            FontWeight="ExtraBold"
                                                            HorizontalAlignment="Center"
                                                            VerticalAlignment="Center"
                                                            Margin="4,2,0,0"/>
                                                        <TextBlock Grid.Row="1" Grid.ColumnSpan="3" HorizontalAlignment="Center"
                                                            Text="{Binding Path=SupportItem.Weight,RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource ShowDouble}, ConverterParameter='##0.00'}"
                                                            Foreground="{TemplateBinding Foreground}" />
                                                    </Grid>
                                                </Border>
                                                <toolkit:ContextMenuService.ContextMenu>
                                                    <toolkit:ContextMenu>
                                                        <toolkit:MenuItem Header="Mark">
                                                            <Custom:Interaction.Triggers>
                                                                <Custom:EventTrigger EventName="Click">
                                                                    <Command:EventToCommand
                                                                    Command="{Binding Path=MarkCommand, Mode=OneWay}"
                                                                    CommandParameter="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ItemDate}" />
                                                                </Custom:EventTrigger>
                                                            </Custom:Interaction.Triggers>
                                                        </toolkit:MenuItem>
                                                        <toolkit:MenuItem Header="Clear">
                                                            <Custom:Interaction.Triggers>
                                                                <Custom:EventTrigger EventName="Click">
                                                                    <Command:EventToCommand
                                                                    Command="{Binding Path=ClearCommand, Mode=OneWay}"
                                                                    CommandParameter="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ItemDate}" />
                                                                </Custom:EventTrigger>
                                                            </Custom:Interaction.Triggers>
                                                        </toolkit:MenuItem>
                                                    </toolkit:ContextMenu>
                                                </toolkit:ContextMenuService.ContextMenu>
                                            </Grid>
                                        </ControlTemplate>
                                    </Setter.Value>
                                </Setter>
                            </Style>

Although it works, I`m more comfortable in changing the CalendarItem using DataTemplate, it much more easier if you we're able to do that.

Anyway, thanks for creating this, and keep up the good work :)

Coordinator
Mar 25, 2012 at 1:49 PM

Hey, Andri. Thanks for the feedback.

The reason I suggested to use alternate style to customize look and feel, is precisely to fit your use case, when you need something else to the display, I am a little surprised that you needed to modify Calendar itself to make that work. Why did you need to do that, I am curious? Since the control is rebuilding UI in the refresh, whatever you bind your Calendar to should just expose your extra property and your template should just consume it via data binding. I.e., your code should have worked without any changes to the calendar. I could certainly add something to the control to keep you from having to modify the class itself, as this was never my intention. Just let me know why you had to modify the code. Also, a sample project (even with hard-coded data) would greatly help me understand your use case.

Sorry I did not reply earlier, somehow I did not get email notification from CodePlex this time around.

Mar 25, 2012 at 5:02 PM

Hi Sergey, Thanks for the reply

Actually, I was trying to create a calendar such as this one (Taken from windows phone marketplace for apps called fertility diary) http://www.appsfuze.com/static/images/apps/0/8/6/08696bb0-752c-e011-854c-00237de2db9e-480x800-2.png

I follow your sample at http://dotnetspeak.com/index.php/2011/01/windows-phone-7-controls-project-update/, in which you show how to implement a background color converter for the calendar, but I'm having trouble when I try to implement a converter which allows me to add picture or show other values other than daynumber

I`ve included my sample project files as well as the modified WPControls in this following link, https://skydrive.live.com/#cid=647341227076C4BA&id=647341227076C4BA!113 with the roughly modified version of WPControls, but I still think that the binding of ISupportCalendarItem to the CalendarItem class is not yet effective, since I can't bind it until the _itemsGrid is filled

Looking forward to hear from you, Thanks

Regards,

Andri Mirandi

Coordinator
Apr 14, 2012 at 6:37 PM

I Hey, Andri.

SOmehow I did not get the email notification, sorry for the delay.  You can do what you need to, but you have to override the template completely and just use databinding, smiliar to how DayNumber is databound in your template and bind to you images, or whatever other visuals you need.  You cannot use the converter in this case, it only handles colors.

Thanks.