[Solved] Combobox show and hide ComboBox items in WPF


Create a custom control such as:

public class CrazyCombo : ComboBox
{
    static CrazyCombo()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(CrazyCombo), new FrameworkPropertyMetadata(typeof(CrazyCombo)));
    }

    public int InitialDisplayItem
    {
        get { return (int)GetValue(InitialDisplayItemProperty); }
        set { SetValue(InitialDisplayItemProperty, value); }
    }

    // Using a DependencyProperty as the backing store for InitialDisplayItem.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty InitialDisplayItemProperty =
        DependencyProperty.Register("InitialDisplayItem", typeof(int), typeof(CrazyCombo), new UIPropertyMetadata(0));

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        var moreLessButton = Template.FindName("moreLessButton", this) as Button;

        moreLessButton.Click += new RoutedEventHandler(moreLessButton_Click);
    }

    void moreLessButton_Click(object sender, RoutedEventArgs e)
    {
        var moreLessButton = Template.FindName("moreLessButton", this) as Button;

        if (moreLessButton.Content.ToString() == "More")
        {
            var icv = CollectionViewSource.GetDefaultView(Items);

            icv.Filter = null;
            moreLessButton.Content = "Less";
        }
        else
        {
            var icv = CollectionViewSource.GetDefaultView(Items);

            icv.Filter += o => Items.OfType<object>().Take(InitialDisplayItem).Contains(o);

            moreLessButton.Content = "More";
        }
    }

    protected override void OnItemsSourceChanged(System.Collections.IEnumerable oldValue, System.Collections.IEnumerable newValue)
    {
        base.OnItemsSourceChanged(oldValue, newValue);

        var icv = CollectionViewSource.GetDefaultView(Items);

        icv.Filter += o => Items.OfType<object>().Take(InitialDisplayItem).Contains(o);
    }

}

In the generic.xaml you will need to put in the entire style for a standard combo box, you can use blend to get it. I won’t post it because it is huuuuuggge. You will need to change the following sections:

Change the style to point at you custom control i.e.

 <Style TargetType="{x:Type local:CrazyCombo}">

In the combo box popup add the more/less button

<Popup x:Name="PART_Popup" AllowsTransparency="true" Grid.ColumnSpan="2" IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}" Margin="1" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Placement="Bottom">
                        <Microsoft_Windows_Themes:SystemDropShadowChrome x:Name="Shdw" Color="Transparent" MaxHeight="{TemplateBinding MaxDropDownHeight}" MinWidth="{Binding ActualWidth, ElementName=MainGrid}">
                            <Border x:Name="DropDownBorder" BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}">
                                <StackPanel>
                                    <ScrollViewer x:Name="DropDownScrollViewer">
                                        <Grid RenderOptions.ClearTypeHint="Enabled">
                                            <Canvas HorizontalAlignment="Left" Height="0" VerticalAlignment="Top" Width="0">
                                                <Rectangle x:Name="OpaqueRect" Fill="{Binding Background, ElementName=DropDownBorder}" Height="{Binding ActualHeight, ElementName=DropDownBorder}" Width="{Binding ActualWidth, ElementName=DropDownBorder}"/>
                                            </Canvas>
                                            <ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Contained" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                                        </Grid>
                                    </ScrollViewer>
                                    <Button Name="moreLessButton" Content="More"/>
                                </StackPanel>
                            </Border>
                        </Microsoft_Windows_Themes:SystemDropShadowChrome>
                    </Popup>

The only addition to the standard combo box control template was the line

<Button Name="moreLessButton" Content="More"/>

You then use the custom control like

<Window x:Class="WpfApplication4.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication4"
    Title="MainWindow" Height="350" Width="525" Foreground="red">

<StackPanel>

    <local:CrazyCombo x:Name="bah" ItemsSource="{Binding Foo}" InitialDisplayItem="1"/>

</StackPanel>

If you were to do this for real you would add some triggers to the button so it only displayed if there were more items then the “InitialDisplayItem”. You would probably also make the button a toggle button instead of my silly switch code.

0

solved Combobox show and hide ComboBox items in WPF