Binding custom dependency property to custom WPF style

18,861

In the style, we can use a standard Binding with a RelativeSource to set up the property.

<ProgressBar Name="ProgressBar"
             Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Progress}"
             Minimum="0"
             Maximum="100" />

Then, in the window we just add Progress="50" or a binding to somewhere else.

You will also need to set the Button's background to transparent, or change some manner of the layout, in order to see it.

Share:
18,861
Alastair Pitts
Author by

Alastair Pitts

Developer. Engineer. Enthusiast. Goodjer. Bugler.

Updated on June 04, 2022

Comments

  • Alastair Pitts
    Alastair Pitts almost 2 years

    I have an issue when designing a inherited Expander. My intention is to have a progress bar behind the toggle button and text in the default Expander header.

    I have this XAML code which gives me the progress bar in the header. It is a custom style.

    <Style x:Key="CurrentScanExpanderStyle" TargetType="{x:Type local:ProgressExpander}">
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
            <Setter Property="VerticalContentAlignment" Value="Stretch"/>
            <Setter Property="BorderBrush" Value="Transparent"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type local:ProgressExpander}">
                        <Border SnapsToDevicePixels="true" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="3">
                            <DockPanel>
                                <Grid DockPanel.Dock="Top">
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="*"/>
                                    </Grid.ColumnDefinitions>
                                    <ProgressBar Name="ProgressBar"/>
                                    <ToggleButton FontFamily="{TemplateBinding FontFamily}" FontSize="{TemplateBinding FontSize}" FontStretch="{TemplateBinding FontStretch}" FontStyle="{TemplateBinding FontStyle}" FontWeight="{TemplateBinding FontWeight}" Foreground="{TemplateBinding Foreground}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" FocusVisualStyle="{StaticResource ExpanderHeaderFocusVisual}" Margin="1" MinHeight="0" MinWidth="0" x:Name="HeaderSite" Style="{StaticResource ExpanderDownHeaderStyle}" IsChecked="{Binding Path=IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Content="{TemplateBinding Header}" ContentTemplate="{TemplateBinding HeaderTemplate}" ContentTemplateSelector="{TemplateBinding HeaderTemplateSelector}"/>
                                </Grid>
                                <ContentPresenter Focusable="false" Visibility="Collapsed" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" x:Name="ExpandSite" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" DockPanel.Dock="Bottom"/>
                            </DockPanel>
                        </Border>
                        <ControlTemplate.Triggers>
                            <!-- Triggers haven't changed from the default -->
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    

    this works fine but I am having trouble binding my custom dependency property which controls the progress percentage.

        public class ProgressExpander : Expander
    {
        static ProgressExpander()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ProgressExpander), new FrameworkPropertyMetadata(typeof(ProgressExpander)));
        }       
    
    
    
        public int Progress
        {
            get { return (int)GetValue(ProgressProperty); }
            set { SetValue(ProgressProperty, value); }
        }
    
        // Using a DependencyProperty as the backing store for Progress.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ProgressProperty =
            DependencyProperty.Register("Progress", typeof(int), typeof(ProgressExpander), new UIPropertyMetadata(0));
    
    
    }
    

    This is the code inside of the window:

                <local:ProgressExpander Grid.Row="1" Header="Current Scan" ExpandDirection="Down" x:Name="currentScanExpander" Style="{DynamicResource CurrentScanExpanderStyle}">
                    <Canvas Background="SkyBlue" 
                            Name="currentScanCanvas"
                            Height="{Binding ElementName=currentScanExpander, Path=ActualWidth}"
                            />
                </local:ProgressExpander>
    

    I'm not sure how to bind this dependency property progress to the progress value in the ProgressBar within the style.

    Any help would be appreciated.

  • Joe White
    Joe White almost 15 years
    Could probably use a TemplateBinding instead; less typing, plus that's what TemplateBinding is for. msdn.microsoft.com/en-us/library/ms742882.aspx
  • rmoore
    rmoore almost 15 years
    There's something wrong with the code as/is that is preventing it from using TemplateBindings, which is why I set it up using the stronger Binding.
  • Alastair Pitts
    Alastair Pitts almost 15 years
    This worked a treat! Iwas having a bunch of problems with the templatebindings... must have been an inheritance thing. Thanks a bundle. =D