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!
JPUser said:Thanks for your reply Andrew. I previously got the scrollbar synchronizing to work, but found that the solution is still not complete. My main problem is that the width of the ScheduleView control seems to be determined when the control is first loaded, and then after that it doesn't matter if the TimeslotInterval is changed, it always stays the same width.
Maybe you can provide a sample that demonstrates the problem. As I mentioned the width of the timeslot is based on the preferred width of a single ScheduleViewTimeslotHeader. The timeslots will be that width unless there is more room than is needed to show all the timeslots - i.e. if the available space for the timeslotpanel is > # timeslots * preferred width.
JPUser said:I'm able to set the width of the ScheduleViewTimeslotHeader, which works properly when the ScheduleView control is first loaded, but then after that if I increase the TimeslotInterval (I have a dropdown box where the user can choose what timeslot interval they'd like to view the control at) the width of ScheduleViewTimeslotHeader automatically changes and the total width of the ScheduleView stays the same. For example, if I change the interval from 1 hours to 2 hours, the ScheduleViewTimeslotHeader width automatically doubles and the total width of the ScheduleView control stays the same. If I decrease the TimeslotInterval instead, for example if I change the interval from 1 hour to 30 minutes, the ScheduleViewTimeslotHeader width stays the same, but the total control width also stays the same so that the scrollbar appears.
I'm not following. If you set the Width then the element will be that size which really isn't a good idea. Rather than trying to guess as to how you have this set up it would be better if you provide a functional sample that demonstrates the issue so I can run it and see the behaviors you are seeing. Then I can make recommendations or explain what is happening.
JPUser said: What I'd like to do is have the total width of the ScheduleView control to recalculate when the TimeslotInterval changes - when the TimeslotInterval increases, I'd like the ScheduleViewTimeslotHeader width to stay the same and the total width of the ScheduleView to decrease. When the TimeslotInterval decreases, I'd like the ScheduleViewTimeslotHeader width to stay the same (as it currently does) but have the total width of the ScheduleView increase.
What I'd like to do is have the total width of the ScheduleView control to recalculate when the TimeslotInterval changes - when the TimeslotInterval increases, I'd like the ScheduleViewTimeslotHeader width to stay the same and the total width of the ScheduleView to decrease. When the TimeslotInterval decreases, I'd like the ScheduleViewTimeslotHeader width to stay the same (as it currently does) but have the total width of the ScheduleView increase.
I'm not sure what you mean by having the width of the control recalculate. Are you putting this into some element that measures the element with infinity (like a horizontal stack panel or grid whose column width is auto?). If so you should be aware that you're disabling any possibility of virtualization. If you are going this route then it's possible you'll need to change some panels being used - like using a Grid with * columns instead of a GridBagPanel as we use in the default template. Maybe your sample will make this clearer.
JPUser said: P.S. is there someway to view your site so that when the window expands the text area also expands? Right now it is quite difficult to view the code you posted as it appears in a narrow, fixed width scroll viewer and there is a huge amount of screen real-estate being taken up by black margins, and if I make my window wider all it does is increase the size of the black margins.
P.S. is there someway to view your site so that when the window expands the text area also expands? Right now it is quite difficult to view the code you posted as it appears in a narrow, fixed width scroll viewer and there is a huge amount of screen real-estate being taken up by black margins, and if I make my window wider all it does is increase the size of the black margins.
Not that I know of. The forums use a fixed width layout.
Thanks for your reply Andrew. I previously got the scrollbar synchronizing to work, but found that the solution is still not complete. My main problem is that the width of the ScheduleView control seems to be determined when the control is first loaded, and then after that it doesn't matter if the TimeslotInterval is changed, it always stays the same width. I'm able to set the width of the ScheduleViewTimeslotHeader, which works properly when the ScheduleView control is first loaded, but then after that if I increase the TimeslotInterval (I have a dropdown box where the user can choose what timeslot interval they'd like to view the control at) the width of ScheduleViewTimeslotHeader automatically changes and the total width of the ScheduleView stays the same. For example, if I change the interval from 1 hours to 2 hours, the ScheduleViewTimeslotHeader width automatically doubles and the total width of the ScheduleView control stays the same. If I decrease the TimeslotInterval instead, for example if I change the interval from 1 hour to 30 minutes, the ScheduleViewTimeslotHeader width stays the same, but the total control width also stays the same so that the scrollbar appears.
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.
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.