I need to create a combo-box that
similar to the "Run" dialog in Windows.
Resizable Completion List:
Drop-down List:
Are there any suitable controls ready in WinForms, WPF, or in any open-source libraries? Or I need to implement it manually using low-level controls?
Thank you in advance!
Answer: We can use “<select> tag” to create combo box. Explanation: Combo box is used to display the drop down list of the options from which we can able to select.
Generally, a combo box is appropriate when there is a list of suggested choices, and a list box is appropriate when you want to limit input to what is on the list. A combo box contains a text box field, so choices not on the list can be typed in. The exception is when the DropDownStyle property is set to DropDownList.
To make a combo box editable, set the IsEditable property to true.
A combo box is a text box with a list box attached. This type of control enables users to select a predefined value in a list or type their own value in the text box portion of the control. The list is hidden until the user clicks the arrow next to the box.
Solution for WPF
Part 1
Principle, you can use styles and templates for the implementation of your question. In the ComboBox
the result is given in the Popup
, but default it does not support changing the size. Add resizing is not difficult, if you use event DragDelta
. Example:
private void MyThumb_DragDelta(object sender, DragDeltaEventArgs e)
{
double yadjust = MyPopup.Height + e.VerticalChange;
double xadjust = MyPopup.Width + e.HorizontalChange;
if ((xadjust >= 0) && (yadjust >= 0))
{
MyPopup.Width = xadjust;
MyPopup.Height = yadjust;
}
}
The event is better to set on the Thumb
control (He also has events DragStarted
, DragCompleted
).
It's all very well, but we do need to do inside the ComboBox
. One way is to use the Style
and Template
. To begin, add a Thumb
in style ComboBox
so it appears in the expanded list:
...
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Grid Name="MainGrid">
<ToggleButton Name="ToggleButton" Template="{StaticResource ComboBoxToggleButton}" Grid.Column="2" Focusable="False" IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press" />
<ContentPresenter Name="ContentSite" IsHitTestVisible="False" Content="{TemplateBinding SelectionBoxItem}" ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" Margin="3,3,23,3" VerticalAlignment="Center" HorizontalAlignment="Left" />
<TextBox x:Name="PART_EditableTextBox" Style="{x:Null}" Template="{StaticResource ComboBoxTextBox}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="3,3,23,3" Focusable="True" Background="{TemplateBinding Background}" Visibility="Hidden" IsReadOnly="{TemplateBinding IsReadOnly}" />
<!-- Expanded list store here -->
<Popup Name="Popup" Placement="Bottom" IsOpen="{TemplateBinding IsDropDownOpen}" AllowsTransparency="True" Focusable="False" PopupAnimation="Slide">
<Grid Name="DropDown" Width="100" Height="100" SnapsToDevicePixels="True">
<Border x:Name="DropDownBorder" Background="White" BorderThickness="1" BorderBrush="Gray" />
<ScrollViewer Margin="2" SnapsToDevicePixels="True">
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
</ScrollViewer>
<!-- Our Thumb -->
<Thumb x:Name="ResizeGripThumb" Style="{StaticResource ResizeGripStyle}" HorizontalAlignment="Right" Margin="0,0,2,2" Background="Transparent" VerticalAlignment="Bottom" Width="12" Height="12" />
</Grid>
</Popup>
</Grid>
...
For normal display Thumb
, add to style it with a Path
:
<!-- ResizeGrip Style -->
<Style x:Key="ResizeGripStyle" TargetType="{x:Type Thumb}">
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Cursor" Value="SizeNWSE" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Grid>
<Path Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" Stretch="Fill" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" Fill="Gray" Data="M8,0L10,0 10,2 8,2z M4,4L6,4 6,6 4,6z M8,4L10,4 10,6 8,6z M0,8L2,8 2,10 0,10z M4,8L6,8 6,10 4,10z M8,8L10,8 10,10 8,10z "/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Now, at this stage, we have shown ResizeGrip
in expanded list. But the default ScrollBar
, then closes it with his presence, so it also define the style for ScrollBar
. It will change the margin VerticalThumb
, thus:
...
<!-- VerticalThumb for ScollBar -->
<Style x:Key="VerticalThumb" TargetType="{x:Type Thumb}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Rectangle Fill="Gray" Margin="-1,-1,-3,16" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Now, there is a normal display of the main components. Declared ComboBox
in XAML:
<ComboBox Name="ResizeComboBox" Style="{StaticResource MyComboBox}" IsEditable="True" IsTextSearchEnabled="True" FontSize="14" SelectedIndex="0" Width="100" Height="30">
<ComboBoxItem>1</ComboBoxItem>
<ComboBoxItem>2</ComboBoxItem>
<ComboBoxItem>3</ComboBoxItem>
<ComboBoxItem>4</ComboBoxItem>
<ComboBoxItem>5</ComboBoxItem>
<ComboBoxItem>6</ComboBoxItem>
<ComboBoxItem>7</ComboBoxItem>
<ComboBoxItem>8</ComboBoxItem>
</ComboBox>
It remains to set a handler for resize the Popup
. I'll make it search-control in the template by using the function FindChild<T>
. To be safe, I'll do it in the event ContentRendered
of Window
, to know that all the elements loaded:
private void Window_ContentRendered(object sender, EventArgs e)
{
// Find MainGrid in our ComboBox template
Grid MyMainGrid = FindChild<Grid>(ResizeComboBox, "MainGrid");
// Find Popup in Grid
Popup MyPopup = MyMainGrid.FindName("Popup") as Popup;
// Find Thumb in Popup
Thumb MyThumb = MyPopup.FindName("ResizeGripThumb") as Thumb;
// Set the handler
MyThumb.DragDelta += new DragDeltaEventHandler(MyThumb_DragDelta);
}
Listing of FindChild<>
:
public static T FindChild<T>(DependencyObject parent, string childName) where T : DependencyObject
{
if (parent == null)
{
return null;
}
T foundChild = null;
int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
T childType = child as T;
if (childType == null)
{
foundChild = FindChild<T>(child, childName);
if (foundChild != null) break;
}
else
if (!string.IsNullOrEmpty(childName))
{
var frameworkElement = child as FrameworkElement;
if (frameworkElement != null && frameworkElement.Name == childName)
{
foundChild = (T)child;
break;
}
else
{
foundChild = FindChild<T>(child, childName);
if (foundChild != null)
{
break;
}
}
}
else
{
foundChild = (T)child;
break;
}
}
return foundChild;
}
Listing of handler MyThumb_DragDelta
:
private void MyThumb_DragDelta(object sender, DragDeltaEventArgs e)
{
Thumb MyThumb = sender as Thumb;
Grid MyGrid = MyThumb.Parent as Grid;
// Set the new Width and Height fo Grid, Popup they will inherit
double yAdjust = MyGrid.Height + e.VerticalChange;
double xAdjust = MyGrid.Width + e.HorizontalChange;
// Set new Height and Width
if ((xAdjust >= 0) && (yAdjust >= 0))
{
MyGrid.Width = xAdjust;
MyGrid.Height = yAdjust;
}
}
It so:
Some notes:
To set the template values, they should have a default value, or the value will be NaN
, and we can not set them. We have these parameters are set here:
<Grid Name="DropDown" Width="100" Height="100" SnapsToDevicePixels="True">
A complete listing of templates and code can be found here, since they are large in volume. Styles can not be easily changed, because they were made in a hurry, so they should do for themselves.
Part 2
As for storing the entered data, it depends on your goals. I think you can do something like this:
ObservableCollection
) to store the items.which he was found
in some sources, save it to your list.ComboBox
.Just set the properties IsEditable
= "True"
and IsTextSearchEnabled
= "True"
to display the input character in the drop-down list (as in my example).
Thus, you will have a list in which the elements are added, which can be shown to the user.
For WindowsForms you need to specify combos properties AutoCompleteSource = AutoCompleteSource.FileSystem and (optionally) AutoCompleteMode = AutoCompleteMode.Suggest. Its "provides a resizable file name completion list".
I do not know a embedded solution for a "keep a history of previous inputs and shows them in a drop-down list".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With