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

Group Header Template problem

3 Answers 220 Views
ScheduleView
This is a migrated thread and some comments may be shown as answers.
Oscar Wahlen
Top achievements
Rank 1
Oscar Wahlen asked on 14 Apr 2011, 03:50 PM
I have a problem with images in group header templates. It seems like the images are not correctly drawn after hiding/showing group descriptions. I've included a very basic example to illustrate the problem. At first the images are shown in the correct group headers. But after checking/unchecking the individual groups a few times the images appear in wrong group headers. The description labels are never displayed in the wrong group headers.

Version: 2011.1.405.1040

MainPage.xaml

<UserControl xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"  x:Class="GroupHeaderTest.MainPage"
    xmlns:local="clr-namespace:GroupHeaderTest"
    mc:Ignorable="d">
      
    <UserControl.Resources>
        <local:MyViewModel x:Key="MyViewModel" />
        <local:ResourceToImageConverter x:Key="ResourceToImageConverter" />
          
        <telerik:OrientedGroupHeaderContentTemplateSelector x:Key="GroupHeaderContentTemplateSelector">
            <telerik:OrientedGroupHeaderContentTemplateSelector.HorizontalDayViewDateTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding Name, StringFormat=%d}" FontWeight="Bold" Margin="4,0,0,0" />
                        <TextBlock Text="{Binding Name, StringFormat=dddd}" Margin="4,0,0,0" />
                    </StackPanel>
                </DataTemplate>
            </telerik:OrientedGroupHeaderContentTemplateSelector.HorizontalDayViewDateTemplate>
            <telerik:OrientedGroupHeaderContentTemplateSelector.HorizontalResourceTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Image Source="{Binding Converter={StaticResource ResourceToImageConverter}}" Height="16" Width="16" Margin="4,0,0,0" />
                        <TextBlock Text="{Binding Name}" Margin="4,0" />
                    </StackPanel>
                </DataTemplate>
            </telerik:OrientedGroupHeaderContentTemplateSelector.HorizontalResourceTemplate>
        </telerik:OrientedGroupHeaderContentTemplateSelector>
    </UserControl.Resources>
      
    <Grid DataContext="{StaticResource MyViewModel}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="100" />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
          
        <StackPanel>
            <StackPanel Orientation="Horizontal">
                <CheckBox IsChecked="{Binding IsBusinessUnitVisible, Mode=TwoWay}">
                    <CheckBox.Content>
                        <TextBlock Text="Business Unit" />
                    </CheckBox.Content>
                </CheckBox>
            </StackPanel>
            <StackPanel Orientation="Horizontal">
                <CheckBox IsChecked="{Binding IsTeamVisible, Mode=TwoWay}">
                    <CheckBox.Content>
                        <TextBlock Text="Team" />
                    </CheckBox.Content>
                </CheckBox>
            </StackPanel>
            <StackPanel Orientation="Horizontal">
                <CheckBox IsChecked="{Binding IsEmployeeVisible, Mode=TwoWay}">
                    <CheckBox.Content>
                        <TextBlock Text="Employee" />
                    </CheckBox.Content>
                </CheckBox>
            </StackPanel>
        </StackPanel>
          
        <telerik:RadScheduleView Grid.Column="1" AppointmentsSource="{Binding Appointments}"
                                 ResourceTypesSource="{Binding ResourcesTypes}"
                                 GroupDescriptionsSource="{Binding GroupDescriptions}"
                                 GroupHeaderContentTemplateSelector="{StaticResource GroupHeaderContentTemplateSelector}">
              
            <telerik:RadScheduleView.ViewDefinitions>
                <telerik:DayViewDefinition GroupFilter="{Binding GroupFilter}" />
            </telerik:RadScheduleView.ViewDefinitions>
              
        </telerik:RadScheduleView>
          
    </Grid>
</UserControl>

MyViewModel.cs

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
  
namespace GroupHeaderTest
{
    using System.ComponentModel;
    using System.Collections.ObjectModel;
    using System.Linq.Expressions;
  
    using Telerik.Windows.Controls;
    using Telerik.Windows.Controls.ScheduleView;
  
    public class MyViewModel : INotifyPropertyChanged
    {
        private bool isBusinessUnitVisible;
        private bool isTeamVisible;
        private bool isEmployeeVisible;
        private ObservableCollection<Appointment> appointments;
        private ObservableCollection<ResourceType> resourceTypes;
        private GroupDescriptionCollection groupDescriptions;
        private Func<object, bool> groupFilter;
  
        public MyViewModel()
        {
            this.isBusinessUnitVisible = true;
            this.isTeamVisible = true;
            this.isEmployeeVisible = true;
            this.appointments = new ObservableCollection<Appointment>();
            this.resourceTypes = new ObservableCollection<ResourceType>();
            this.groupDescriptions = new GroupDescriptionCollection() { new DateGroupDescription() };
            this.groupFilter = new Func<object, bool>(this.GroupFilterFunc);
            this.UpdateGroupDescriptions();
            this.UpdateResourceTypes();
        }
  
        public bool IsBusinessUnitVisible
        {
            get { return this.isBusinessUnitVisible; }
            set
            {
                this.isBusinessUnitVisible = value;
                this.OnPropertyChanged(() => this.IsBusinessUnitVisible);
                this.UpdateGroupDescriptions();
            }
        }
  
        public bool IsTeamVisible
        {
            get { return this.isTeamVisible; }
            set
            {
                this.isTeamVisible = value;
                this.OnPropertyChanged(() => this.IsTeamVisible);
                this.UpdateGroupDescriptions();
            }
        }
  
        public bool IsEmployeeVisible
        {
            get { return this.isEmployeeVisible; }
            set
            {
                this.isEmployeeVisible = value;
                this.OnPropertyChanged(() => this.IsEmployeeVisible);
                this.UpdateGroupDescriptions();
            }
        }
  
        public ObservableCollection<Appointment> Appointments
        {
            get { return this.appointments; }
            set
            {
                this.appointments = value;
            }
        }
  
        public ObservableCollection<ResourceType> ResourcesTypes
        {
            get { return this.resourceTypes; }
            set
            {
                this.resourceTypes= value;
            }
        }
  
        public GroupDescriptionCollection GroupDescriptions
        {
            get { return this.groupDescriptions; }
            set
            {
                this.groupDescriptions = value;
            }
        }
  
        private bool GroupFilterFunc(object groupName)
        {
            if (groupName is DateTime)
            {
                return true;
            }
            return true;
        }
  
        private void UpdateGroupDescriptions()
        {
            this.GroupDescriptions.RemoveAll((GroupDescription g) => g is ResourceGroupDescription);
            if (this.IsBusinessUnitVisible)
            {
                this.GroupDescriptions.Add(new ResourceGroupDescription() { ResourceType = "Business Unit" });
            }
            if (this.IsTeamVisible)
            {
                this.GroupDescriptions.Add(new ResourceGroupDescription() { ResourceType = "Team" });
            }
            if (this.IsEmployeeVisible)
            {
                this.GroupDescriptions.Add(new ResourceGroupDescription() { ResourceType = "Employee" });
            }
        }
  
        public void UpdateResourceTypes()
        {
            ResourceType businessUnitType = new ResourceType("Business Unit");
            businessUnitType.Resources.Add(new Resource("Contoso"));
  
            ResourceType teamType = new ResourceType("Team");
            teamType.Resources.Add(new Resource("Development"));
            teamType.Resources.Add(new Resource("Sales"));
  
            ResourceType employeeType = new ResourceType("Employee");
            employeeType.Resources.Add(new Resource("April Meyer"));
            employeeType.Resources.Add(new Resource("Lisa Andrews"));
  
            this.ResourcesTypes.Add(businessUnitType);
            this.ResourcesTypes.Add(teamType);
            this.ResourcesTypes.Add(employeeType);
        }
  
        #region INotifyPropertyChanged Members
  
        public event PropertyChangedEventHandler PropertyChanged;
  
        #endregion
  
        public void OnPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
  
        public void OnPropertyChanged<T>(Expression<Func<T>> propertyExpression)
        {
            this.OnPropertyChanged(((MemberExpression)propertyExpression.Body).Member.Name);
        }
    }
}

ResourceToImageConverter.cs

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
  
namespace GroupHeaderTest
{
    using System.Windows.Data;
    using System.Windows.Media.Imaging;
  
    using Telerik.Windows.Controls;
    using Telerik.Windows.Controls.ScheduleView;
  
    public class ResourceToImageConverter : IValueConverter
    {
  
        #region IValueConverter Members
  
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (targetType == typeof(ImageSource) && value is GroupHeaderProxy)
            {
                IResource res = (value as GroupHeaderProxy).Name as IResource;
                if (res.ResourceType == "Business Unit")
                {
                    return new BitmapImage(new Uri("/GroupHeaderTest;component/businessunit.png", UriKind.RelativeOrAbsolute));
                }
                if (res.ResourceType == "Team")
                {
                    return new BitmapImage(new Uri("/GroupHeaderTest;component/team.png", UriKind.RelativeOrAbsolute));
                }
                if (res.ResourceType == "Employee")
                {
                    return new BitmapImage(new Uri("/GroupHeaderTest;component/employee.png", UriKind.RelativeOrAbsolute));
                }
            }
            throw new NotImplementedException();
        }
  
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
  
        #endregion
    }
}

3 Answers, 1 is accepted

Sort by
0
Oscar Wahlen
Top achievements
Rank 1
answered on 19 Apr 2011, 12:52 PM
While debugging I noticed the convert method of my converter is called only once (after the ScheduleView is loaded).
0
Pana
Telerik team
answered on 20 Apr 2011, 07:10 AM
Hi,

I hoped the problem is in your core but then I've found:

this

 

 

.OnPropertyChanged(() => this.IsTeamVisible);

 

in your project. You are probably the first customer I see using it although we have it implemented in the public Telerik.WindowsControls.ViewModelBase. I wonder why you are not extending it. Anyway, good for you and bad for us:

I have reproduced the issue. I believe during virtualization the GroupHeaders are recycled and obviously the DataTemplate selector is not reapplied when recycled GroupHeaders are reused.

As we have put extra effort in making the RadScheduleView customizable through Style and DataTemplate selectors I believe this bug will be handled with high priority and I hope fix will be released in the internal build after the easter holidays.

Greetings,
Pana
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
Oscar Wahlen
Top achievements
Rank 1
answered on 20 Apr 2011, 09:55 AM
Thank you for your effort.

I think I've got it working now. Instead of binding directly to the DataContext it is now bound to the GroupHeaderProxy's Name property. I am not sure if this is XAML specific behavior but for some reason the convert method of my custom converter was not executed when the Source property was bound to the DataContext.

<Image Source="{Binding Name, Converter={StaticResource ResourceToImageConverter}}" Height="16" Width="16" Margin="4,0,0,0" />

This does not entirely solve my problem though. In my custom control template I want to bind to the GroupHeader's ParentKeys property (http://www.telerik.com/community/forums/silverlight/scheduleview/multilevel-resource-grouping-parent.aspx). This does not work if the DataTemplate/Style selector is not reapplied.

<TextBlock Text="{Binding ParentKeys[1], RelativeSource={RelativeSource TemplatedParent}}" />

Is there a workaround?
Tags
ScheduleView
Asked by
Oscar Wahlen
Top achievements
Rank 1
Answers by
Oscar Wahlen
Top achievements
Rank 1
Pana
Telerik team
Share this question
or