0
votes

So I have the following xaml code in wpf. Which gives me a DropdownButton behaving as I would expect it.

<ToggleButton Content="Test"
                  VerticalAlignment="Center"
                  Focusable="False"
                  IsChecked="{Binding IsOpen, ElementName=Popup, Mode=TwoWay}"
                  Height="25"
                  Width="20"
                  x:Name="btn">
        <ToggleButton.Style>
            <Style TargetType="{x:Type ToggleButton}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding IsOpen, ElementName=Popup}" Value="True">
                        <Setter Property="IsHitTestVisible" Value="False" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </ToggleButton.Style>
    </ToggleButton>

    <Popup Placement="Bottom"
           PlacementTarget="{Binding ElementName=btn}"
           x:Name="Popup"
           StaysOpen="False">
        <TextBlock Background="AliceBlue">Bla</TextBlock>
    </Popup>

now since I use this a couple of times I wanted to create a custom Control.

So far the class looks like this:

public class CustomDropdownButton : ToggleButton
{
    public static readonly DependencyProperty DropdownContentProperty = DependencyProperty.Register("DropdownContent", typeof(UIElement), typeof(CustomDropdownButton));

    static CustomDropdownButton()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomDropdownButton), new FrameworkPropertyMetadata(typeof(CustomDropdownButton)));
    }

    public UIElement DropdownContent
    {
        get
        {
            return (UIElement)GetValue(DropdownContentProperty);
        }
        set
        {
            SetValue(DropdownContentProperty, value);
        }
    }
}

and I edited the style, it looks like this:

<Style x:Key="ButtonFocusVisual">
    <Setter Property="Control.Template">
        <Setter.Value>
            <ControlTemplate>
                <Rectangle StrokeDashArray="1 2" StrokeThickness="1" 
                           Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" 
                           SnapsToDevicePixels="true" Margin="2"/>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
<LinearGradientBrush x:Key="ButtonNormalBackground" EndPoint="0,1" StartPoint="0,0">
    <GradientStop Color="#F3F3F3" Offset="0"/>
    <GradientStop Color="#EBEBEB" Offset="0.5"/>
    <GradientStop Color="#DDDDDD" Offset="0.5"/>
    <GradientStop Color="#CDCDCD" Offset="1"/>
</LinearGradientBrush>
<SolidColorBrush x:Key="ButtonNormalBorder" Color="#FF707070"/>

<Style TargetType="{x:Type local:CustomDropdownButton}">
    <Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisual}"/>
    <Setter Property="Background" Value="{StaticResource ButtonNormalBackground}"/>
    <Setter Property="BorderBrush" Value="{StaticResource ButtonNormalBorder}"/>
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
    <Setter Property="HorizontalContentAlignment" Value="Center"/>
    <Setter Property="VerticalContentAlignment" Value="Center"/>
    <Setter Property="Padding" Value="1"/>
    <Setter Property="ClickMode" Value="Press"/>
    <Setter Property="Focusable" Value="False"/>
    <Setter Property="IsChecked" Value="{Binding IsOpen, ElementName=Popup, Mode=TwoWay}"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:CustomDropdownButton}">

                <themes:ButtonChrome x:Name="Chrome"
                                     BorderBrush="{TemplateBinding BorderBrush}"
                                     Background="{TemplateBinding Background}"
                                     RenderMouseOver="{TemplateBinding IsMouseOver}"
                                     SnapsToDevicePixels="true">
                    <StackPanel Orientation="Horizontal"
                                IsHitTestVisible="True">
                        <ContentPresenter Content="{TemplateBinding Content}"
                                          HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                          VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                          Margin="5,0,0,0"/>
                        <Path x:Name="ArrowPath"
                              Margin="7,3,3,2"
                              Fill="Gray"
                              Stroke="Gray"
                              StrokeThickness="1"
                              StrokeStartLineCap="Round"
                              StrokeEndLineCap="Round"
                              Stretch="Uniform"
                              VerticalAlignment="Center"
                              HorizontalAlignment="Center"
                              RenderTransformOrigin=".5,.5"
                              Data="M0,0 L2,0 L4,2 L5,3 L6,2 L8,0 L10,0 L8,2 L5,7 L2,2 z">
                            <Path.RenderTransform>
                                <RotateTransform Angle="-90"/>
                            </Path.RenderTransform>
                        </Path>

                        <Popup Placement="Bottom"
                               x:Name="Popup"
                               StaysOpen="False"
                               Child="{TemplateBinding DropdownContent}"/>
                    </StackPanel>
                </themes:ButtonChrome>

                <ControlTemplate.Triggers>
                    <DataTrigger Binding="{Binding IsOpen, ElementName=Popup}" Value="True">
                        <Setter Property="IsHitTestVisible" Value="False" />
                    </DataTrigger>
                    <Trigger Property="IsKeyboardFocused" Value="true">
                        <Setter Property="RenderDefaulted" TargetName="Chrome" Value="true"/>
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="false">
                        <Setter Property="Foreground" Value="#ADADAD"/>
                    </Trigger>
                    <Trigger Property="IsChecked" Value="False">
                        <Trigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation Storyboard.TargetName="ArrowPath"
                                                     Storyboard.TargetProperty="RenderTransform.(RotateTransform.Angle)"
                                                     To="-90"
                                                     Duration="0:0:0.2"/>
                                </Storyboard>
                            </BeginStoryboard>
                        </Trigger.EnterActions>
                        <Trigger.ExitActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimation Storyboard.TargetName="ArrowPath"
                                                     Storyboard.TargetProperty="RenderTransform.(RotateTransform.Angle)"
                                                     To="0"
                                                     Duration="0:0:0.2"/>
                                </Storyboard>
                            </BeginStoryboard>
                        </Trigger.ExitActions>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

The example code for the popup button worked just fine. I thought I would get the same effect by using a Setter to bind the IsOpen Property of the popup to the IsChecked Property of the ToggleButton.

Am I missing trigger behaviour I need to add? I can't quite figure out why it won't open.


Fixed it by removing the IsChecked and ClickMode Setter, bound the IsOpen property from the popup not with templatebinding but with the suggested RelativeSource Binding to the IsChecked, with Mode set to TwoWay. StaysOpen and the DataTrigger were kept.

Popup still closed because of a margin I set for the ListViewItems in the ListView. Set a Padding (always clickable) or Margin(hitting nothing) for the content holder. For me it was a Checkbox inside the ListView.

1

1 Answers

1
votes

Bind the IsOpen property of the Popup in the template to the IsChecked property of the control:

<Popup Placement="Bottom"
        x:Name="Popup"
        StaysOpen="False"
        IsOpen="{Binding Path=IsChecked, RelativeSource={RelativeSource AncestorType=local:CustomDropdownButton}, Mode=TwoWay}"
        Child="{TemplateBinding DropdownContent}"/>

This won't work:

<Setter Property="IsChecked" Value="{Binding IsOpen, ElementName=Popup, Mode=TwoWay}"/>