65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIconstarIcon

5.00/5 (7投票s)

2016年9月27日

CPOL

1分钟阅读

viewsIcon

13579

downloadIcon

133

这是“如何将任意内容嵌入 WPF 控件”的替代方案

背景

我正在研究如何在 Control 中嵌入内容,发现了这篇文章,并使用了其中包含的 CustomControl,该文章是 如何在 WPF 控件中嵌入任意内容,作者是 。在使用这个解决方案时,我遇到一个问题,那就是 Binding。Ivan Krivyokov 在他的文章和示例中没有涉及这个主题。

引言

我需要一个带有按钮的水平 ScrollBarScrollViewer。因此,本文将重点介绍在 ScrollViewer 中创建嵌入内容。

控件

该控件由两部分组成:一个从 ScrollViewer 派生的 C# class,以及相关的 XAMLC# 代码是

    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

每当 ScrollBarToolsScrollBarToolsDataContext 发生更改时,ScrollBarToolsDataContext 就会被设置。如果指定了 ScrollBarToolsDataContext,则将其设置为 DataContext,否则将 ScrollViewerDataContext 设置为 ScrollBarToolsDataContext。有趣的是,如果未设置 ScrollBarToolsDataContext,那么 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:初始版本。

© . All rights reserved.