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!
No. The activities are positioned at the pixel associated with their start time. Just as with Outlook if activities in a schedule view overlap then they are shifted to another row.
Ok, but as you can see in the screenshots, the times of the schedules are not actually overlapping, they are consecutive...
If you want to retemplate it then you would look in the DefaultStyles directory for the xamSchedule's xaml and create your own style/template based on the ones there.
Thank you, I'll give it a try.
Finally, one more question for today - how can I set the interval at which the header labels appear? For example, in the screenshot above the header text is appearing every hour. I'd like to change this value when the timeslot interval is changed (showing the time only at the hour level is not ideal when the timeslot interval is 1 minute...). I tried to find where this value is set, but I can't seem to find it anywhere.
JPUser said:Is there some way to do something about this so that the side-by-side appointments don't stack up on top of each other when the interval increases?
JPUser said:Or if it's not possible, is there someway to at least prevent it from stacking on multiple levels so that those little arrows are necessary to view the rest of the levels?
The out of view indicators are their when there is not enough room to show all the activities. The height of the control does not currently consider the height of the activities since the control is designed to virtualize the timeslots and activities and because each CalendarGroup is intended to be the same size. We can try to see if this is something we can support but I cannot say for sure that we can.
JPUser said:On a related note, how is the style of an appointment set (or more specifically, the height)? I inherited maintenance of this screen and the person who initially set up this control is not here anymore. I've tried to find where the style is set but haven't been successful so far..
An Appointment is represented by an AppointmentPresenter. The style and template for the AppointmentPresenter ultimately dictate the size. If you want to retemplate it then you would look in the DefaultStyles directory for the xamSchedule's xaml and create your own style/template based on the ones there. The activities are relatively complicated because they are responsible for lots of things so their template is somewhat complicated.
Thank you, that solution was exactly what I was hoping for!
Now that the scrolling issue is solved I've noticed another small issue. It has to do with the way short side-by-side appointments are displayed when the timeslot interval gets bigger. For example, If I create a number of 1 or 2 minute long appointments beside each other and then change the timeslot interval, they start stacking on top of each other. For example:
A number of short appointments created beside each other with the interval set to 1 minute.
When the interval is changed to 15 minutes the appointments start stacking on top of each other...
Then at 60 minutes it starts stacking on multiple levels so that a little arrow appears at the bottom of the ScheduleView to show the rest of the levels (3 in all, shown in the above 3 screen shots).
Is there some way to do something about this so that the side-by-side appointments don't stack up on top of each other when the interval increases? Or if it's not possible, is there someway to at least prevent it from stacking on multiple levels so that those little arrows are necessary to view the rest of the levels? I think we could possibly handle the way it looks at a 15 minute interval, but I have a feeling that the way it looks at 60 minutes with the little arrows will not work for the users.
On a related note, how is the style of an appointment set (or more specifically, the height)? I inherited maintenance of this screen and the person who initially set up this control is not here anymore. I've tried to find where the style is set but haven't been successful so far...
Ok so you have the controls within an element that is measuring its children with infinity? E.g. a horizontal stackpanel (stackpanels only measure with infinity in the direction they are arranging and width the value of the availablesize for the other constraint), a grid where the associated column definition has a width of auto, a scrollviewer where the horizontalscrollbarvisibility is auto, hidden or visible. Note, just having it within a window whose SizeToContent is Width is not enough because in that case the Window measures its children with the virtual screen width - not infinity. In that situation then the desired size should be based upon the default/preferred timeslotheader width * the number of timeslots so the control width should change.
I tried this out and currently it won't when using our GridBagPanel in the control template but if you change it to Grid and change the attached properties used in the template then it does. It is important to note though that if the width of the ancestor is less than the desired width then part of the control will be off screen. If you put it in a scrollviewer as you seem to indicate you are doing then you will be able to scroll the contents but realize that (a) there will no virtualization of elements since virtualization is based on being measured with the actual on screen available size and (b) if the scrollviewer will contain the xamschedule views then it will be scrolling the entire control and therefore the tabs on the left will scroll out of view.
Here's a modified version of the style I provided earlier but this one uses a Grid instead of a GridBagPanel.
<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" > <Grid igPrim:XamlHelper.SnapsToDevicePixels="{TemplateBinding igPrim:XamlHelper.SnapsToDevicePixels}"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <TextBlock Text="{TemplateBinding SecondaryTimeZoneLabel}" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="0,6,8,0" Grid.Row="0" Grid.Column="0" Visibility="{TemplateBinding SecondaryTimeZoneVisibility}" /> <TextBlock Text="{TemplateBinding PrimaryTimeZoneLabel}" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="0,6,8,0" Grid.Row="1" Grid.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" Grid.Row="0" Grid.Column="2" Visibility="{TemplateBinding SecondaryTimeZoneVisibility}" /> <igPrim:ScheduleViewTimeslotHeaderArea x:Name="PrimaryTimeZone" Background="{Binding Path=DefaultBrushProvider[TimeslotHeaderAreaBackgroundScheduleView], RelativeSource={RelativeSource TemplatedParent}}" Grid.Row="1" Grid.Column="2" /> <igPrim:ScheduleStackPanel x:Name="GroupHeadersPanel" Grid.Row="2" Grid.Column="0" Visibility="{TemplateBinding CalendarHeaderAreaVisibilityResolved}" /> <igPrim:ScheduleStackPanel x:Name="GroupsPanel" Grid.Row="2" Grid.Column="2" /> <ScrollBar Grid.Column="3" Grid.Row="2" Orientation="Vertical" Style="{TemplateBinding ScrollBarStyle}" x:Name="TimeslotGroupScrollBar" /> <ScrollBar Grid.Column="2" Grid.Row="3" Orientation="Horizontal" Style="{TemplateBinding ScrollBarStyle}" MinHeight="0" Height="{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}}" Grid.Row="0" Grid.Column="1" Grid.RowSpan="4" 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" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" Grid.RowSpan="4" HorizontalAlignment="Right" /> </Grid> <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>
<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" > <Grid igPrim:XamlHelper.SnapsToDevicePixels="{TemplateBinding igPrim:XamlHelper.SnapsToDevicePixels}"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <TextBlock Text="{TemplateBinding SecondaryTimeZoneLabel}" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="0,6,8,0" Grid.Row="0" Grid.Column="0" Visibility="{TemplateBinding SecondaryTimeZoneVisibility}" /> <TextBlock Text="{TemplateBinding PrimaryTimeZoneLabel}" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="0,6,8,0" Grid.Row="1" Grid.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" Grid.Row="0" Grid.Column="2" Visibility="{TemplateBinding SecondaryTimeZoneVisibility}" /> <igPrim:ScheduleViewTimeslotHeaderArea x:Name="PrimaryTimeZone" Background="{Binding Path=DefaultBrushProvider[TimeslotHeaderAreaBackgroundScheduleView], RelativeSource={RelativeSource TemplatedParent}}" Grid.Row="1" Grid.Column="2" />
<igPrim:ScheduleStackPanel x:Name="GroupHeadersPanel" Grid.Row="2" Grid.Column="0" Visibility="{TemplateBinding CalendarHeaderAreaVisibilityResolved}" />
<igPrim:ScheduleStackPanel x:Name="GroupsPanel" Grid.Row="2" Grid.Column="2" />
<ScrollBar Grid.Column="3" Grid.Row="2" Orientation="Vertical" Style="{TemplateBinding ScrollBarStyle}" x:Name="TimeslotGroupScrollBar" /> <ScrollBar Grid.Column="2" Grid.Row="3" Orientation="Horizontal" Style="{TemplateBinding ScrollBarStyle}" MinHeight="0" Height="{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}}" Grid.Row="0" Grid.Column="1" Grid.RowSpan="4" 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" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" Grid.RowSpan="4" HorizontalAlignment="Right" /> </Grid>
<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>
Considering how long it would take for me to make a working sample of this program, I'd like to leave that as a final resort. Instead I've added some screen captures to help explain what I'm talking about.
This first screen capture shows the setup with the TimeslotInterval set to 30 minutes. Basically I have a vertical stack panel containing a dynamic number of ScheduleView control's, each control representing a single day running from 5:00 - 5:00 (the next day). The date range is selected at the top left (max 7 days), and the TimeslotInterval is selected from the dropdown at the top right. The interval was set to 30 minutes when the ScheduleView controls were loaded, so the width of the ScheduleView controls is the exact width needed to display the control with the ScheduleViewTimeslotHeader width set to the value specified in the ScheduleView's style.
The second screen capture shows what happens when the TimeslotInterval is changed to 60 minutes - the ScheduleViewTimeslotHeader width automatically doubles and the total width of the ScheduleView controls stays exactly the same. Even though the timeslot interval is twice as big as in the previous screen capture, from the user's point of view the appearance of the control is basically the same between the two, just with less lines in the latter screen...
What I would like to happen would be that the ScheduleViewTimeslotHeader width stays the same as in the first screen capture and instead the total width of the ScheduleView controls reduces by half (like in the last screen capture).
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.
So when this happens is there a way to make it so the available space for the timeslotpanel is set to (# timeslots * preferred width) so that it doesn't stretch everything?
The third screen capture shows what happens when the TimeslotInterval is changed to 15 minutes - the ScheduleViewTimeslotHeader width stays the same, the total width of the ScheduleView controls also stays exactly the same, and a scrollbar appears to allow scrolling to the right to view the rest of the day's schedule.
What I'd like to happen here would be, instead of the total width of the ScheduleView control staying the same and a scrollbar appearing, I'd like to have the total width of the ScheduleView control double and then I could scroll all the days at once using the scrollbar of the stackpanel in which the ScheduleView controls are all inside of.
I'm not sure what you mean by having the width of the control recalculate.
I mean I'd like the width demonstrated in the screen capture above to change so that it's always 100% the width of the ScheduleView, without needed to scroll the ScheduleView, and without the width of the ScheduleViewTimeslotHeader changing to make it expand to a certain width. As you can see in all the screen captures the width of the ScheduleView controls is exactly the same no matter what the interval (and also no matter the size of the window). This width seems to be calculated once when the ScheduleView control is loaded, and then it never changes after that. If I load the control again with a different interval set, then the total width of the ScheduleView control changes (shown in the screen capture below where the ScheduleView controls were loaded with the TimeslotInterval set to 60 minutes). I'd like to have this width change when the TimeslotInterval is changed.