如何将任意内容嵌入 WPF 控件并进行绑定





5.00/5 (7投票s)
这是“如何将任意内容嵌入 WPF 控件”的替代方案
背景
我正在研究如何在 Control
中嵌入内容,发现了这篇文章,并使用了其中包含的 CustomControl,该文章是 如何在 WPF 控件中嵌入任意内容,作者是 。在使用这个解决方案时,我遇到一个问题,那就是 Binding
。Ivan Krivyokov 在他的文章和示例中没有涉及这个主题。
引言
我需要一个带有按钮的水平 ScrollBar
的 ScrollViewer
。因此,本文将重点介绍在 ScrollViewer
中创建嵌入内容。
控件
该控件由两部分组成:一个从 ScrollViewer
派生的 C# class
,以及相关的 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.
// This enables animation, styling, binding, etc...
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
。一个用于水平 ScrollBar
右侧的内容,水平 ScrollBar
的宽度会根据 UIElement
及其内容进行调整。UIElement
可以包含一个 Panel
,例如 StackPanel
,其中可以包含控件,例如 Button
控件。第二个允许为这些工具中指定的内容设置 DataContext
。
每当 ScrollBarTools
或 ScrollBarToolsDataContext
发生更改时,ScrollBarTools
的 DataContext
就会被设置。如果指定了 ScrollBarToolsDataContext
,则将其设置为 DataContext
,否则将 ScrollViewer
的 DataContext
设置为 ScrollBarTools
的 DataContext
。有趣的是,如果未设置 ScrollBarTools
的 DataContext
,那么 DataContext
将是 ScrollBarToolsScrollViewer
。
我从现有代码中提取了 ScrollViewer
的样式,该样式位于 Themes 文件夹中的 Generic.xaml 文件中
<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>
ScrollBarTools
的位置在一个添加的 Grid 元素中,该元素包含水平 ScrollBar
和新的 ScrollBarTools
。由于此 Style
依赖于为 ScrollBar
定义的现有默认 Style
,因此它应该与设计中的其他 ScrollViewer
元素非常相似。
历史
2016/09/27:初始版本。