Search code examples
c#wpfcomboboxsplit-buttonwpf-extended-toolkit

Extended Toolkit SplitButton: use ComboBox ItemsSource as DropDownContent


I'd like to refactor my code in order to use Extended Toolkit SplitButton instead of Standard Combobox.

Here is my initial working code:

<ComboBox ItemsSource="{Binding Path=VisualizationList, Mode=TwoWay}">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <TextBlock
                    Text="{Binding Converter={StaticResource MultiLangConverter}/>
            </StackPanel>
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

And here is my SplitButton

<xctk:SplitButton Content="Click Me">
    <xctk:SplitButton.DropDownContent>
        <!-- What should I use here? -->
    </xctk:SplitButton.DropDownContent>
</xctk:SplitButton>

Now, I'd like to set something like ItemsSource to SplitButton in order to make it behave like a standard ComboBox button. Is there a way to get such behaviour?

If you need it, here is the style with the ControlTemplate of my SplitButton.

<ControlTemplate x:Key="SplitButtonTemplate" TargetType="xctk:SplitButton">
<Grid x:Name="MainGrid" SnapsToDevicePixels="True">
    <xctk:ButtonChrome x:Name="ControlChrome" Background="{TemplateBinding Background}"
                       RenderEnabled="{TemplateBinding IsEnabled}">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>
            <Button x:Name="PART_ActionButton"
                    Margin="0"
                    HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                    VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
                    Padding="{TemplateBinding Padding}"
                    Tag="{TemplateBinding Tag}"
                    Style="{StaticResource BlackButton}">
                <ContentPresenter Name="ActionButtonContent" Margin="{TemplateBinding Padding}"
                                          Content="{TemplateBinding Content}"
                                          ContentTemplate="{TemplateBinding ContentTemplate}"
                                          VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                          HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                          RecognizesAccessKey="true" />
            </Button>
            <ToggleButton x:Name="PART_ToggleButton"
                          Grid.Column="1"
                          IsTabStop="False"
                          IsChecked="{Binding IsOpen, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}">
                <ToggleButton.Template>
                    <ControlTemplate TargetType="ToggleButton">
                        <ContentPresenter />
                    </ControlTemplate>
                </ToggleButton.Template>
                <Grid>
                    <xctk:ButtonChrome x:Name="ToggleButtonChrome"
                                       RenderNormal="False"
                                       RenderChecked="{TemplateBinding IsOpen}"
                                       RenderEnabled="{TemplateBinding IsEnabled}"
                                       RenderMouseOver="{Binding IsMouseOver, ElementName=PART_ToggleButton}"
                                       RenderPressed="{Binding IsPressed, ElementName=PART_ToggleButton}">
                        <Grid x:Name="arrowGlyph" IsHitTestVisible="False" Margin="15,6,15,6">
                            <Path Width="7" Height="4"
                                  Data="M 0,1 C0,1 0,0 0,0 0,0 3,0 3,0 3,0 3,1 3,1 3,1 4,1 4,1 4,1 4,0 4,0 4,0 7,0 7,0 7,0 7,1 7,1 7,1 6,1 6,1 6,1 6,2 6,2 6,2 5,2 5,2 5,2 5,3 5,3 5,3 4,3 4,3 4,3 4,4 4,4 4,4 3,4 3,4 3,4 3,3 3,3 3,3 2,3 2,3 2,3 2,2 2,2 2,2 1,2 1,2 1,2 1,1 1,1 1,1 0,1 0,1 z"
                                      Fill="White" />
                            </Grid>
                        </xctk:ButtonChrome>
                    </Grid>
                </ToggleButton>
            </Grid>
        </xctk:ButtonChrome>
        <Popup IsOpen="{Binding IsChecked, ElementName=PART_ToggleButton}"
               AllowsTransparency="True"
               PopupAnimation="Slide">
            <Grid x:Name="DropDown"
                  MinWidth="{TemplateBinding ActualWidth}"
                  MaxHeight="{TemplateBinding MaxDropDownHeight}">
                <Border x:Name="DropDownBorder" BorderBrush="{StaticResource StandardBorderColor}"
                        Background="{StaticResource ComboBoxBackgroundColor}" />
                <ScrollViewer>
                    <ContentPresenter Content="{TemplateBinding DropDownContent}" />
                </ScrollViewer>
            </Grid>
        </Popup>
    </Grid>
</ControlTemplate>
<Style TargetType="xctk:SplitButton">
    <Setter Property="Template" Value="{StaticResource SplitButtonTemplate}" />
</Style>

Solution

  • One way would be to add a ListBox as the content of your SplitButton.

    You will have to add custom code as needed to get the exact behavior you want, but here is an example to get you started:

    <xctk:SplitButton x:Name="btnSplit" Content="Select a product...">
        <xctk:SplitButton.DropDownContent>
            <ListBox ItemsSource="..."
                     SelectionChanged="ListBox_SelectionChanged">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding ProductName}" />
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </xctk:SplitButton.DropDownContent>
    </xctk:SplitButton>
    
    private void ListBox_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
    {
        ListBox content = (ListBox)sender;
        btnSplit.Content = ((DataRowView)content.SelectedItem)["ProductName"].ToString();
        btnSplit.IsOpen = false;
    }