Hello,
Is there someway to hide the scrollbar of the XamScheduleView? I have a stackpanel with multiple XamScheduleView's, each scheduleview representing one day, stacked on top of each other vertically. I'd like to have it so that the individual scheduleview's don't have a scrollbar and instead use the scrollbar of the stackpanel to navigate horizontally - this way as I scroll I can view the same time period for all the day's at the same time.
During debugging I've found the TimeslotScrollBarVisibility property, and when set to Hidden it does what I'm looking for, but I can't figure out a way to access this property in code/XAML.
Alternatively, having someway to synchronize the scrollbars together would accomplish the same goal. Is there anyway to synchronize the scrollbars of XamScheduleViews? (Although with this solution I'd still like to hide the individual scrollbars and only have a single scrollbar that controls the scrolling for all the scheduleviews.)
Thank you!
Well, I've figured out to get rid of the scrollbar by creating a custom ControlTemplate, but it doesn't do any good because the control still behaves the way it would if the scrollbar existed - i.e. the control's width doesn't resize when you change the interval.
Is there someway to define the width of the XamScheduleView, or make it so that the control is always 100% of it's width (so there's no scrolling needed from the control's scrollbar)? The width property always seems to be set to "NaN". If I could dynamically resize the control when the interval is changed then I think I'd be able to come up with a solution that will work for me.
A scrollbar is used to expose the scroll range - not define it - if that is what you mean. This is the same in any scrollable control. In the case of the xamSchedule the timeslots are a minimum width based on the preferrred width of a ScheduleViewTimeslotHeader. If there is less room than required to show all the timeslots horizontally using that value then scrolling is enabled whether a scrollbar is present or not. I thought you wanted to have the scrolling of all synchronized but only shown in 1 control. If you want that you should just create some attached properties to help with that. For example, you might create one for the scrollbar offset. You can use a two-way binding between the offset of the scrollbar to the control and then two way bind between that property on the control and another xamschedule. e.g.
<Grid xmlns:tshelper="clr-namespace:ScheduleHelper"> <Grid.Resources> <igPrim:ScheduleResourceString x:Key="BlockingErrorLiteral" ResourceName="BlockingErrorLiteral"/> <igPrim:ValueConverterGroup x:Key="nullToVisibility"> <!-- if null sets visibility to Collapsed --> <igPrim:FixedValueConverter SourceValue="{x:Null}"> <igPrim:FixedValueConverter.DestinationValue> <Visibility>Collapsed</Visibility> </igPrim:FixedValueConverter.DestinationValue> </igPrim:FixedValueConverter> <!-- if not null sets visibility to Visible --> <igPrim:FixedValueConverter> <igPrim:FixedValueConverter.DestinationValue> <Visibility>Visible</Visibility> </igPrim:FixedValueConverter.DestinationValue> </igPrim:FixedValueConverter> </igPrim:ValueConverterGroup> <Style x:Key="BlockingErrorStyle" TargetType="ContentControl"> <!-- AS 12/16/10 TFS61923 --> <Setter Property="igPrim:XamlHelper.Focusable" Value="False"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ContentControl"> <Grid > <Grid.RowDefinitions> <RowDefinition Height ="Auto"/> <RowDefinition Height ="Auto"/> <RowDefinition Height ="*"/> </Grid.RowDefinitions> <Rectangle Grid.RowSpan="3" Opacity=".9" Fill="{Binding Path=(igPrim:CalendarBrushProvider.BrushProvider)[BlockingErrorBackground], RelativeSource={RelativeSource TemplatedParent}}"/> <!--Header--> <ContentControl Grid.Row="0" FontWeight="Bold" Foreground="{Binding Path=(igPrim:CalendarBrushProvider.BrushProvider)[BlockingErrorHeaderForeground], RelativeSource={RelativeSource TemplatedParent}}" Content="{Binding Source={StaticResource BlockingErrorLiteral}, Path=Value}" Margin="5"> <ContentControl.FontSize> <Binding Path="FontSize" RelativeSource="{RelativeSource TemplatedParent}"> <Binding.Converter> <igPrim:MinMaxConverter MinValue="14"/> </Binding.Converter> </Binding> </ContentControl.FontSize> <!-- JJD 9/19/11 - TFS87912 Use binding instead to the Value property of the ScheduleResourceString so we can get notified when the resources are changed. <igPrim:ScheduleResourceString ResourceName="BlockingErrorLiteral"/>--> </ContentControl> <!--Description--> <TextBlock Grid.Row="1" Margin="5,0,5,0" FontWeight="Bold" TextWrapping="Wrap" Foreground="{Binding Path=(igPrim:CalendarBrushProvider.BrushProvider)[BlockingErrorForeground], RelativeSource={RelativeSource TemplatedParent}}" Text="{Binding Path=Content.UserErrorText, RelativeSource={RelativeSource TemplatedParent}}" Visibility="{Binding Path=Content.UserErrorText, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource nullToVisibility}}" > <TextBlock.FontSize> <Binding Path="FontSize" RelativeSource="{RelativeSource TemplatedParent}"> <Binding.Converter> <igPrim:MinMaxConverter MinValue="12.5"/> </Binding.Converter> </Binding> </TextBlock.FontSize> </TextBlock> <!--Details--> <ScrollViewer Grid.Row="2" Margin="5" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"> <TextBox Text="{Binding Path=Content, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" Foreground="{Binding Path=(igPrim:CalendarBrushProvider.BrushProvider)[BlockingErrorForeground], RelativeSource={RelativeSource TemplatedParent}}" IsReadOnly="True" TextWrapping="Wrap" Background="{x:Null}"/> </ScrollViewer> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> <Style TargetType="ig:XamScheduleView"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ig:XamScheduleView"> <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" igPrim:XamlHelper.SnapsToDevicePixels="True"> <VisualStateManager.VisualStateGroups> <VisualStateGroup Name="ErrorStates"> <VisualState Name="NoError"/> <VisualState Name="Error"> <Storyboard Storyboard.TargetName="ErrorDisplay" Storyboard.TargetProperty="Visibility"> <ObjectAnimationUsingKeyFrames> <DiscreteObjectKeyFrame KeyTime="0"> <DiscreteObjectKeyFrame.Value> <Visibility>Visible</Visibility> </DiscreteObjectKeyFrame.Value> </DiscreteObjectKeyFrame> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Grid x:Name="RootPanel" > <ig:GridBagPanel igPrim:XamlHelper.SnapsToDevicePixels="{TemplateBinding igPrim:XamlHelper.SnapsToDevicePixels}"> <TextBlock Text="{TemplateBinding SecondaryTimeZoneLabel}" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="0,6,8,0" ig:GridBagPanel.Row="0" ig:GridBagPanel.Column="0" Visibility="{TemplateBinding SecondaryTimeZoneVisibility}" /> <TextBlock Text="{TemplateBinding PrimaryTimeZoneLabel}" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="0,6,8,0" ig:GridBagPanel.Row="1" ig:GridBagPanel.Column="0" /> <igPrim:ScheduleViewTimeslotHeaderArea x:Name="SecondaryTimeZone" Background="{Binding Path=DefaultBrushProvider[TimeslotHeaderAreaBackgroundScheduleView], RelativeSource={RelativeSource TemplatedParent}}" BorderBrush="{Binding Path=DefaultBrushProvider[TimeslotHeaderAreaSeparator], RelativeSource={RelativeSource TemplatedParent}}" BorderThickness="0,0,0,1" ig:GridBagPanel.Row="0" ig:GridBagPanel.Column="2" Visibility="{TemplateBinding SecondaryTimeZoneVisibility}" ig:GridBagPanel.ColumnWeight="1" /> <igPrim:ScheduleViewTimeslotHeaderArea x:Name="PrimaryTimeZone" Background="{Binding Path=DefaultBrushProvider[TimeslotHeaderAreaBackgroundScheduleView], RelativeSource={RelativeSource TemplatedParent}}" ig:GridBagPanel.Row="1" ig:GridBagPanel.Column="2" ig:GridBagPanel.ColumnWeight="1" /> <igPrim:ScheduleStackPanel x:Name="GroupHeadersPanel" ig:GridBagPanel.Row="2" ig:GridBagPanel.Column="0" ig:GridBagPanel.RowWeight="1" Visibility="{TemplateBinding CalendarHeaderAreaVisibilityResolved}" /> <igPrim:ScheduleStackPanel x:Name="GroupsPanel" ig:GridBagPanel.Row="2" ig:GridBagPanel.Column="2" ig:GridBagPanel.ColumnWeight="1" ig:GridBagPanel.RowWeight="1" /> <ScrollBar ig:GridBagPanel.Column="3" ig:GridBagPanel.Row="2" Orientation="Vertical" Style="{TemplateBinding ScrollBarStyle}" x:Name="TimeslotGroupScrollBar" ig:GridBagPanel.RowWeight="1" /> <ScrollBar ig:GridBagPanel.Column="2" ig:GridBagPanel.Row="3" ig:GridBagPanel.ColumnWeight="1" Orientation="Horizontal" Style="{TemplateBinding ScrollBarStyle}" MinHeight="0" ig:GridBagPanel.PreferredHeight="{TemplateBinding tshelper:TimeslotHelper.ScrollBarHeight}" Value="{Binding Path=(tshelper:TimeslotHelper.ScrollBarOffset), RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}" x:Name="TimeslotScrollBar" /> <Rectangle igPrim:XamlHelper.SnapsToDevicePixels="True" Fill="{Binding Path=DefaultBrushProvider[TimeslotHeaderTickmarkScheduleView], RelativeSource={RelativeSource TemplatedParent}}" ig:GridBagPanel.Row="0" ig:GridBagPanel.Column="1" ig:GridBagPanel.RowSpan="4" ig:GridBagPanel.ColumnWeight="0" ig:GridBagPanel.PreferredWidth="1" Width="2"/> <!-- AS 11/11/10 NA 11.1 - CalendarHeaderAreaWidth --> <!-- Overlap the rectangle above. --> <igPrim:ScheduleResizerBar x:Name="GroupHeadersResizer" IsEnabled="{TemplateBinding AllowCalendarHeaderAreaResizing}" Canvas.ZIndex="2" Width="4" ig:GridBagPanel.Column="0" ig:GridBagPanel.ColumnSpan="2" ig:GridBagPanel.Row="0" ig:GridBagPanel.RowSpan="4" HorizontalAlignment="Right" /> </ig:GridBagPanel> <ContentControl x:Name="ErrorDisplay" Visibility="Collapsed" Content="{Binding Path=BlockingError, RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource BlockingErrorStyle}" igPrim:CalendarBrushProvider.BrushProvider="{Binding Path=DefaultBrushProvider, RelativeSource={RelativeSource TemplatedParent}}" /> </Grid> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> </Grid.Resources> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition /> <RowDefinition /> <RowDefinition /> </Grid.RowDefinitions> <ig:XamScheduleView DataManager="{Binding ElementName=dm}" x:Name="sv1" Grid.Row="0" tshelper:TimeslotHelper.ScrollBarHeight="0" tshelper:TimeslotHelper.ScrollBarOffset="{Binding ElementName=sv4, Mode=TwoWay, Path=(tshelper:TimeslotHelper.ScrollBarOffset)}" /> <ig:XamScheduleView DataManager="{Binding ElementName=dm}" x:Name="sv2" Grid.Row="1" tshelper:TimeslotHelper.ScrollBarHeight="0" tshelper:TimeslotHelper.ScrollBarOffset="{Binding ElementName=sv4, Mode=TwoWay, Path=(tshelper:TimeslotHelper.ScrollBarOffset)}" /> <ig:XamScheduleView DataManager="{Binding ElementName=dm}" x:Name="sv3" Grid.Row="2" tshelper:TimeslotHelper.ScrollBarHeight="0" tshelper:TimeslotHelper.ScrollBarOffset="{Binding ElementName=sv4, Mode=TwoWay, Path=(tshelper:TimeslotHelper.ScrollBarOffset)}" /> <ig:XamScheduleView DataManager="{Binding ElementName=dm}" x:Name="sv4" Grid.Row="3" /> </Grid>
<igPrim:ValueConverterGroup x:Key="nullToVisibility"> <!-- if null sets visibility to Collapsed --> <igPrim:FixedValueConverter SourceValue="{x:Null}"> <igPrim:FixedValueConverter.DestinationValue> <Visibility>Collapsed</Visibility> </igPrim:FixedValueConverter.DestinationValue> </igPrim:FixedValueConverter>
<!-- if not null sets visibility to Visible --> <igPrim:FixedValueConverter> <igPrim:FixedValueConverter.DestinationValue> <Visibility>Visible</Visibility> </igPrim:FixedValueConverter.DestinationValue> </igPrim:FixedValueConverter>
</igPrim:ValueConverterGroup>
<Style x:Key="BlockingErrorStyle" TargetType="ContentControl"> <!-- AS 12/16/10 TFS61923 --> <Setter Property="igPrim:XamlHelper.Focusable" Value="False"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ContentControl"> <Grid > <Grid.RowDefinitions> <RowDefinition Height ="Auto"/> <RowDefinition Height ="Auto"/> <RowDefinition Height ="*"/> </Grid.RowDefinitions>
<Rectangle Grid.RowSpan="3" Opacity=".9" Fill="{Binding Path=(igPrim:CalendarBrushProvider.BrushProvider)[BlockingErrorBackground], RelativeSource={RelativeSource TemplatedParent}}"/>
<!--Header--> <ContentControl Grid.Row="0" FontWeight="Bold" Foreground="{Binding Path=(igPrim:CalendarBrushProvider.BrushProvider)[BlockingErrorHeaderForeground], RelativeSource={RelativeSource TemplatedParent}}" Content="{Binding Source={StaticResource BlockingErrorLiteral}, Path=Value}" Margin="5"> <ContentControl.FontSize> <Binding Path="FontSize" RelativeSource="{RelativeSource TemplatedParent}"> <Binding.Converter> <igPrim:MinMaxConverter MinValue="14"/> </Binding.Converter> </Binding> </ContentControl.FontSize> <!-- JJD 9/19/11 - TFS87912 Use binding instead to the Value property of the ScheduleResourceString so we can get notified when the resources are changed. <igPrim:ScheduleResourceString ResourceName="BlockingErrorLiteral"/>--> </ContentControl>
<!--Description--> <TextBlock Grid.Row="1" Margin="5,0,5,0" FontWeight="Bold" TextWrapping="Wrap" Foreground="{Binding Path=(igPrim:CalendarBrushProvider.BrushProvider)[BlockingErrorForeground], RelativeSource={RelativeSource TemplatedParent}}" Text="{Binding Path=Content.UserErrorText, RelativeSource={RelativeSource TemplatedParent}}" Visibility="{Binding Path=Content.UserErrorText, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource nullToVisibility}}" > <TextBlock.FontSize> <Binding Path="FontSize" RelativeSource="{RelativeSource TemplatedParent}"> <Binding.Converter> <igPrim:MinMaxConverter MinValue="12.5"/> </Binding.Converter> </Binding> </TextBlock.FontSize>
</TextBlock>
<!--Details--> <ScrollViewer Grid.Row="2" Margin="5" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<TextBox Text="{Binding Path=Content, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" Foreground="{Binding Path=(igPrim:CalendarBrushProvider.BrushProvider)[BlockingErrorForeground], RelativeSource={RelativeSource TemplatedParent}}" IsReadOnly="True" TextWrapping="Wrap" Background="{x:Null}"/>
</ScrollViewer>
</Grid>
</ControlTemplate> </Setter.Value> </Setter> </Style>
<Style TargetType="ig:XamScheduleView"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ig:XamScheduleView"> <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" igPrim:XamlHelper.SnapsToDevicePixels="True">
<VisualStateManager.VisualStateGroups> <VisualStateGroup Name="ErrorStates"> <VisualState Name="NoError"/> <VisualState Name="Error"> <Storyboard Storyboard.TargetName="ErrorDisplay" Storyboard.TargetProperty="Visibility"> <ObjectAnimationUsingKeyFrames> <DiscreteObjectKeyFrame KeyTime="0"> <DiscreteObjectKeyFrame.Value> <Visibility>Visible</Visibility> </DiscreteObjectKeyFrame.Value> </DiscreteObjectKeyFrame> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups>
<Grid x:Name="RootPanel" > <ig:GridBagPanel igPrim:XamlHelper.SnapsToDevicePixels="{TemplateBinding igPrim:XamlHelper.SnapsToDevicePixels}"> <TextBlock Text="{TemplateBinding SecondaryTimeZoneLabel}" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="0,6,8,0" ig:GridBagPanel.Row="0" ig:GridBagPanel.Column="0" Visibility="{TemplateBinding SecondaryTimeZoneVisibility}" /> <TextBlock Text="{TemplateBinding PrimaryTimeZoneLabel}" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="0,6,8,0" ig:GridBagPanel.Row="1" ig:GridBagPanel.Column="0" />
<igPrim:ScheduleViewTimeslotHeaderArea x:Name="SecondaryTimeZone" Background="{Binding Path=DefaultBrushProvider[TimeslotHeaderAreaBackgroundScheduleView], RelativeSource={RelativeSource TemplatedParent}}" BorderBrush="{Binding Path=DefaultBrushProvider[TimeslotHeaderAreaSeparator], RelativeSource={RelativeSource TemplatedParent}}" BorderThickness="0,0,0,1" ig:GridBagPanel.Row="0" ig:GridBagPanel.Column="2" Visibility="{TemplateBinding SecondaryTimeZoneVisibility}" ig:GridBagPanel.ColumnWeight="1" /> <igPrim:ScheduleViewTimeslotHeaderArea x:Name="PrimaryTimeZone" Background="{Binding Path=DefaultBrushProvider[TimeslotHeaderAreaBackgroundScheduleView], RelativeSource={RelativeSource TemplatedParent}}" ig:GridBagPanel.Row="1" ig:GridBagPanel.Column="2" ig:GridBagPanel.ColumnWeight="1" />
<igPrim:ScheduleStackPanel x:Name="GroupHeadersPanel" ig:GridBagPanel.Row="2" ig:GridBagPanel.Column="0" ig:GridBagPanel.RowWeight="1" Visibility="{TemplateBinding CalendarHeaderAreaVisibilityResolved}" />
<igPrim:ScheduleStackPanel x:Name="GroupsPanel" ig:GridBagPanel.Row="2" ig:GridBagPanel.Column="2" ig:GridBagPanel.ColumnWeight="1" ig:GridBagPanel.RowWeight="1" />
<ScrollBar ig:GridBagPanel.Column="3" ig:GridBagPanel.Row="2" Orientation="Vertical" Style="{TemplateBinding ScrollBarStyle}" x:Name="TimeslotGroupScrollBar" ig:GridBagPanel.RowWeight="1" /> <ScrollBar ig:GridBagPanel.Column="2" ig:GridBagPanel.Row="3" ig:GridBagPanel.ColumnWeight="1" Orientation="Horizontal" Style="{TemplateBinding ScrollBarStyle}" MinHeight="0" ig:GridBagPanel.PreferredHeight="{TemplateBinding tshelper:TimeslotHelper.ScrollBarHeight}" Value="{Binding Path=(tshelper:TimeslotHelper.ScrollBarOffset), RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}" x:Name="TimeslotScrollBar" /> <Rectangle igPrim:XamlHelper.SnapsToDevicePixels="True" Fill="{Binding Path=DefaultBrushProvider[TimeslotHeaderTickmarkScheduleView], RelativeSource={RelativeSource TemplatedParent}}" ig:GridBagPanel.Row="0" ig:GridBagPanel.Column="1" ig:GridBagPanel.RowSpan="4" ig:GridBagPanel.ColumnWeight="0" ig:GridBagPanel.PreferredWidth="1" Width="2"/>
<!-- AS 11/11/10 NA 11.1 - CalendarHeaderAreaWidth --> <!-- Overlap the rectangle above. --> <igPrim:ScheduleResizerBar x:Name="GroupHeadersResizer" IsEnabled="{TemplateBinding AllowCalendarHeaderAreaResizing}" Canvas.ZIndex="2" Width="4" ig:GridBagPanel.Column="0" ig:GridBagPanel.ColumnSpan="2" ig:GridBagPanel.Row="0" ig:GridBagPanel.RowSpan="4" HorizontalAlignment="Right" /> </ig:GridBagPanel>
<ContentControl x:Name="ErrorDisplay" Visibility="Collapsed" Content="{Binding Path=BlockingError, RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource BlockingErrorStyle}" igPrim:CalendarBrushProvider.BrushProvider="{Binding Path=DefaultBrushProvider, RelativeSource={RelativeSource TemplatedParent}}" />
</Grid> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> </Grid.Resources> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition /> <RowDefinition /> <RowDefinition /> </Grid.RowDefinitions> <ig:XamScheduleView DataManager="{Binding ElementName=dm}" x:Name="sv1" Grid.Row="0" tshelper:TimeslotHelper.ScrollBarHeight="0" tshelper:TimeslotHelper.ScrollBarOffset="{Binding ElementName=sv4, Mode=TwoWay, Path=(tshelper:TimeslotHelper.ScrollBarOffset)}" /> <ig:XamScheduleView DataManager="{Binding ElementName=dm}" x:Name="sv2" Grid.Row="1" tshelper:TimeslotHelper.ScrollBarHeight="0" tshelper:TimeslotHelper.ScrollBarOffset="{Binding ElementName=sv4, Mode=TwoWay, Path=(tshelper:TimeslotHelper.ScrollBarOffset)}" /> <ig:XamScheduleView DataManager="{Binding ElementName=dm}" x:Name="sv3" Grid.Row="2" tshelper:TimeslotHelper.ScrollBarHeight="0" tshelper:TimeslotHelper.ScrollBarOffset="{Binding ElementName=sv4, Mode=TwoWay, Path=(tshelper:TimeslotHelper.ScrollBarOffset)}" /> <ig:XamScheduleView DataManager="{Binding ElementName=dm}" x:Name="sv4" Grid.Row="3" /> </Grid>
The TimeslotHelper referenced here is just a simple class with some attached properties. e.g.
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Windows; namespace ScheduleHelper{ public static class TimeslotHelper { #region ScrollBarHeight public static readonly DependencyProperty ScrollBarHeightProperty = DependencyProperty.RegisterAttached("ScrollBarHeight", typeof(double), typeof(TimeslotHelper), new PropertyMetadata(double.NaN) ); public static double GetScrollBarHeight(DependencyObject d) { return (double)d.GetValue(TimeslotHelper.ScrollBarHeightProperty); } public static void SetScrollBarHeight(DependencyObject d, double value) { d.SetValue(TimeslotHelper.ScrollBarHeightProperty, value); } #endregion //ScrollBarHeight #region ScrollBarOffset public static readonly DependencyProperty ScrollBarOffsetProperty = DependencyProperty.RegisterAttached("ScrollBarOffset", typeof(double), typeof(TimeslotHelper), new PropertyMetadata(0d) ); public static double GetScrollBarOffset(DependencyObject d) { return (double)d.GetValue(TimeslotHelper.ScrollBarOffsetProperty); } public static void SetScrollBarOffset(DependencyObject d, double value) { d.SetValue(TimeslotHelper.ScrollBarOffsetProperty, value); } #endregion //ScrollBarOffset }}
namespace ScheduleHelper{ public static class TimeslotHelper { #region ScrollBarHeight
public static readonly DependencyProperty ScrollBarHeightProperty = DependencyProperty.RegisterAttached("ScrollBarHeight", typeof(double), typeof(TimeslotHelper), new PropertyMetadata(double.NaN) );
public static double GetScrollBarHeight(DependencyObject d) { return (double)d.GetValue(TimeslotHelper.ScrollBarHeightProperty); }
public static void SetScrollBarHeight(DependencyObject d, double value) { d.SetValue(TimeslotHelper.ScrollBarHeightProperty, value); }
#endregion //ScrollBarHeight
#region ScrollBarOffset
public static readonly DependencyProperty ScrollBarOffsetProperty = DependencyProperty.RegisterAttached("ScrollBarOffset", typeof(double), typeof(TimeslotHelper), new PropertyMetadata(0d) );
public static double GetScrollBarOffset(DependencyObject d) { return (double)d.GetValue(TimeslotHelper.ScrollBarOffsetProperty); }
public static void SetScrollBarOffset(DependencyObject d, double value) { d.SetValue(TimeslotHelper.ScrollBarOffsetProperty, value); }
#endregion //ScrollBarOffset }}
What is happening is that you set the attached ScrollBarHeight on each xamSchedule (except the last) to 0. The template has the preferredheight of the scrollbar bound to that property (and the Minimum of the scrollbar set to 0 since the default style has it set to 17 or maybe its a system value). That allows you to hide the scrollbar from each but the last control. Then the Value property of the ScrollBar is two way bound to the control using the other attached property - ScrollBarOffset. Then each instance of the xamScheduleView has that property two way bound to the last xamSchedule so the scrolling is synchronized.
Note if you want to see the xamSchedule showing each day on a separate row I would recommend submitting a suggestion for adding this though since it would probably be best if the control did it since it could support any # of days whereas you need to have a control for each and manage the VisibleDates of each. Also, it would allow selection across the days whereas in this case each control has its own selection, edit state, active group, etc. If you do submit a suggestion please be sure to include as much detail as possible as there are many interpretations of this type of behavior - e.g. I would expect that if we did this in the control that the day header identifying which day's timeslots are displayed would be to the left side of the timeslots similar to how the day header in day view is fixed at the top of the vertically scrolling timeslots.