I have a long Scroll Viewer and I want to mark important spots with small images on the scroll bar. If the the image is clicked the scroll bar will jump to the corresponding con
Short answer is "change the template of the ScrollBar".
Long answer is... That I would add an ItemsControl in the template of the ScrollBar control. I would put this ItemsControl on top of the template with its IsHitTestVisible set to false so that it does not capture mouse events.
Then I would use a Canvas as the ItemsPanelTemplate in order to be able to place the spots properly. I would use databinding with the ItemsSource property of the ItemsControl and a DataTemplate in order to render each element with an image.
Here is a sample that I did using Blend. Of course it's not complete (it does not handle mouse event for example), but I hope it will be a starting point for you.
(source: japf.fr)
<ControlTemplate TargetType="{x:Type ScrollBar}">
<Grid SnapsToDevicePixels="true" Background="{TemplateBinding Background}">
<Grid.ColumnDefinitions>
<ColumnDefinition MaxWidth="{DynamicResource {x:Static SystemParameters.HorizontalScrollBarButtonWidthKey}}"/>
<ColumnDefinition Width="0.00001*"/>
<ColumnDefinition MaxWidth="{DynamicResource {x:Static SystemParameters.HorizontalScrollBarButtonWidthKey}}"/>
</Grid.ColumnDefinitions>
<RepeatButton Style="{StaticResource ScrollBarButton}" Command="{x:Static ScrollBar.LineLeftCommand}" Microsoft_Windows_Themes:ScrollChrome.ScrollGlyph="LeftArrow"/>
<Track x:Name="PART_Track" Grid.Column="1" d:IsHidden="True">
<Track.Thumb>
<Thumb Style="{StaticResource ScrollBarThumb}" Microsoft_Windows_Themes:ScrollChrome.ScrollGlyph="HorizontalGripper"/>
</Track.Thumb>
<Track.IncreaseRepeatButton>
<RepeatButton Style="{StaticResource HorizontalScrollBarPageButton}" Command="{x:Static ScrollBar.PageRightCommand}"/>
</Track.IncreaseRepeatButton>
<Track.DecreaseRepeatButton>
<RepeatButton Style="{StaticResource HorizontalScrollBarPageButton}" Command="{x:Static ScrollBar.PageLeftCommand}"/>
</Track.DecreaseRepeatButton>
</Track>
<ItemsControl Grid.Column="1" HorizontalAlignment="Stretch">
<sys:Double>10</sys:Double>
<sys:Double>50</sys:Double>
<sys:Double>100</sys:Double>
<sys:Double>140</sys:Double>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Rectangle Fill="Orange" Width="3" Height="16"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding }" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<RepeatButton Style="{StaticResource ScrollBarButton}" Grid.Column="2" Command="{x:Static ScrollBar.LineRightCommand}" Microsoft_Windows_Themes:ScrollChrome.ScrollGlyph="RightArrow" d:IsHidden="True"/>
</Grid>
</ControlTemplate>
To contribute to japfs answer: I solved the update on resize issue: You can use japfs Style and apply a ItemsSource to the ItemControl:
ItemsSource="{Binding Positions, UpdateSourceTrigger=PropertyChanged}"
Just make sure Positions is of type ObservableCollection and the positions are recalculated in SizeChanged-event. Additionally in that event call (INotifyPropertyChanged interface which should your ViewModel implement)
OnPropertyChanged("Positions");
Tried it with a List first, but that did not update correctly. Worked with ObservableCollection just fine.