Click here to Skip to main content
15,124,972 members
Articles / Desktop Programming / WPF
Alternative
Article
Posted 27 Sep 2016

Tagged as

Stats

10.4K views
92 downloads
7 bookmarked

How to Embed Arbitrary Content in a WPF Control with Binding

Rate me:
Please Sign up or sign in to vote.
5.00/5 (7 votes)
27 Sep 2016CPOL1 min read
This is an alternative for "How to Embed Arbitrary Content in a WPF Control"

Background

I was looking at how to embed content in a Control, and found this article, and used the CustomControl that was included in the How to Embed Arbitrary Content in a WPF Control by , I had one issue with this particular solution and that was Binding. Ivan Krivyokov did not broach this subject in his article and sample.

Introduction

I needed a ScrollViewer with some buttons in the Horizontal ScrollBar. Therefore this article will focus on creating embedded content in a ScrollViewer.

The Control

The control consists of two parts, the C# class derived from a ScrollViewer, and the associated XAML. The C# code is:

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;
    }
}

This code adds two DependencyProperties to the ScrollViewer. One is for the content to be to the right of the horizontal ScrollBar, the horizontal ScrollBar width being adjusted to accomodate the UIElement and its content. The UIElement can contain a Panel such as a StackPanel, which can contain controls, such as Button controls. The second allows the DataContext for the content specified in these tools.

Whenever the ScrollBarTools or ScrollBarToolsDataContext is changed, the DataContext for the ScrollBarTools is set. If a ScrollBarToolsDataContext is specified, that is set as the DataContext, otherwise the DataContext of the ScrollViewer is set as the DataContext of the ScrollBarTools. Interestingly, if the DataContext for the ScrollBarTools was not set, then the DataContext would be the ScrollBarToolsScrollViewer.

I pulled the Style for ScrollViewer that is in the Generic.xaml file in the Themes folder from existing code:

XML
<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>

The location for the ScrollBarTools is in an added Grid element that contains the horizontal ScrollBar and the new ScrollBarTools. Since this Style depends on existing default Style defined for the ScrollBar, it should look very similar to the other ScrollViewer elements in the design.

Image 1

History

2016/09/27: Initial Version.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Clifford Nelson
Software Developer (Senior) Clifford Nelson Consulting
United States United States
Has been working as a C# developer on contract for the last several years, including 3 years at Microsoft. Previously worked with Visual Basic and Microsoft Access VBA, and have developed code for Word, Excel and Outlook. Started working with WPF in 2007 when part of the Microsoft WPF team. For the last eight years has been working primarily as a senior WPF/C# and Silverlight/C# developer. Currently working as WPF developer with BioNano Genomics in San Diego, CA redesigning their UI for their camera system. he can be reached at qck1@hotmail.com.

Comments and Discussions

 
QuestionNice work, and small edit req. Pin
John Schroedl3-Oct-16 6:23
professionalJohn Schroedl3-Oct-16 6:23 
Good job and thanks for writing this up!

One small edit for readability in this sentence would help -- fix "the the" to?? "be the"???

"...if the DataContext for the ScrollBarTools was not set, then the DataContext would the the ScrollBarToolsScrollViewer."

John
AnswerRe: Nice work, and small edit req. Pin
Clifford Nelson3-Oct-16 13:48
MemberClifford Nelson3-Oct-16 13:48 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.