问题
ComboBox might have a lot of items.
This is the scenario i would like to achieve:
I have to create a custom ComboBox
which has a "More" button which located at the last of the ComboBox
items. If the ComboBox
contain of 20 items, initially, when the ComboBox
is clicked and the drop down list is shown, there are only 10 items and a "More" button under the 10th items are displayed.
Whenever the "More" button items is clicked, the "More" button will turn into "Less" and the drop down list will display total of 20 items. So when "Less" button is clicked, the display items will be reversed back to 10 items and the another 10 items will be hidden.
The 10 initial display items is just an example. Actually, The total of the ComboBox's
initial display item can be set through the property.
For example: <local:CustomComboBox x:Name="CustomComboBox" InitialDisplayItem="10" />
I am new to wpf...How can i achieve that?
回答1:
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.
来源:https://stackoverflow.com/questions/11680660/combobox-show-and-hide-combobox-items-in-wpf