在开发WPF应用程序时,经常需要在滚动视图控件中嵌入一些自定义的内容。本文将介绍如何实现这一功能,包括创建一个自定义的ScrollViewer控件,并在其中嵌入一些按钮到水平滚动条中。
这个自定义的ScrollViewer控件由两部分组成:一个是C#类,它继承自ScrollViewer;另一个是与之关联的XAML。以下是C#类的代码实现:
public class ScrollBarToolsScrollViewer : ScrollViewer
{
static ScrollBarToolsScrollViewer()
{
DefaultStyleKeyProperty.OverrideMetadata(
typeof(ScrollBarToolsScrollViewer),
new FrameworkPropertyMetadata(
typeof(ScrollBarToolsScrollViewer)));
}
public object ScrollBarTools
{
get { return (object)GetValue(ScrollBarToolsProperty); }
set { SetValue(ScrollBarToolsProperty, value); }
}
// Using a DependencyProperty as the backing store for ScrollBarTools.
public static readonly DependencyProperty ScrollBarToolsProperty =
DependencyProperty.Register(
"ScrollBarTools",
typeof(object),
typeof(ScrollBarToolsScrollViewer),
new UIPropertyMetadata(null, OnScrollBarToolsChanged));
private static void OnScrollBarToolsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var scrollViewer = (ScrollBarToolsScrollViewer)d;
var control = e.NewValue as FrameworkElement;
if (control != null)
{
if (scrollViewer.ScrollBarToolsDataContext == null) control.DataContext = scrollViewer.DataContext;
else control.DataContext = scrollViewer.ScrollBarToolsDataContext;
}
}
public object ScrollBarToolsDataContext
{
get { return (object)GetValue(ViewBarToolsDataContextProperty); }
set { SetValue(ViewBarToolsDataContextProperty, value); }
}
// Using a DependencyProperty as the backing store for ScrollBarToolsDataContext.
public static readonly DependencyProperty ViewBarToolsDataContextProperty =
DependencyProperty.Register(
"ViewBarToolsDataContext",
typeof(object),
typeof(ScrollBarToolsScrollViewer),
new PropertyMetadata(null, OnScrollBarToolsDataContextChanged));
private static void OnScrollBarToolsDataContextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var scrollViewer = (ScrollBarToolsScrollViewer)d;
var control = scrollViewer.ScrollBarTools as FrameworkElement;
if (control != null)
{
if (scrollViewer.ScrollBarToolsDataContext == null) control.DataContext = scrollViewer.DataContext;
else control.DataContext = scrollViewer.ScrollBarToolsDataContext;
}
}
}
这段代码为ScrollViewer添加了两个DependencyProperties。一个用于在水平滚动条右侧放置内容,水平滚动条的宽度会根据UIElement及其内容进行调整。UIElement可以包含一个Panel,如StackPanel,它又可以包含控件,如Button控件。第二个DependencyProperty允许为这些工具指定DataContext。
每当ScrollBarTools或ScrollBarToolsDataContext发生变化时,都会设置ScrollBarTools的DataContext。如果指定了ScrollBarToolsDataContext,则将其设置为DataContext;否则,将ScrollViewer的DataContext设置为ScrollBarTools的DataContext。有趣的是,如果未设置ScrollBarTools的DataContext,则DataContext将是ScrollBarToolsScrollViewer。
从Themes文件夹中的Generic.xaml文件中提取了ScrollViewer的样式,这是现有的代码:
<Style x:Key="{x:Type local:ScrollBarToolsScrollViewer}" TargetType="{x:Type local:ScrollBarToolsScrollViewer}">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ScrollBarToolsScrollViewer}">
<Grid Background="Transparent">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ScrollContentPresenter x:Name="PART_ScrollContentPresenter" Margin="{TemplateBinding Padding}" CanContentScroll="{TemplateBinding CanContentScroll}" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}"/>
<ScrollBar x:Name="PART_VerticalScrollBar" Grid.Column="1" AutomationProperties.AutomationId="VerticalScrollBar" Cursor="Arrow" Maximum="{TemplateBinding ScrollableHeight}" Minimum="0.0" ViewportSize="{TemplateBinding ViewportHeight}" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=VerticalOffset, Mode=OneWay}"/>
<Grid Grid.Row="1" Grid.Column="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<ScrollBar x:Name="PART_HorizontalScrollBar" AutomationProperties.AutomationId="HorizontalScrollBar" Cursor="Arrow" Maximum="{TemplateBinding ScrollableWidth}" Minimum="0.0" Orientation="Horizontal" ViewportSize="{TemplateBinding ViewportWidth}" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=HorizontalOffset, Mode=OneWay}"/>
<ContentPresenter Grid.Column="1" ContentSource="ScrollBarTools" DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}"/>
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>