WPF 的解决方案
Part 1
原则上,您可以使用样式和模板来实现您的问题。在ComboBox 中,结果在Popup 中给出,但默认不支持更改大小。如果您使用事件DragDelta,添加调整大小并不困难。示例:
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;
}
}
事件最好设置在Thumb控件上(他也有事件DragStarted,DragCompleted)。
一切都很好,但我们确实需要在ComboBox 内做。一种方法是使用Style 和Template。首先,在ComboBox 样式中添加Thumb,使其出现在展开的列表中:
...
<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>
...
为了正常显示Thumb,使用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>
现在,在这个阶段,我们在扩展列表中显示了ResizeGrip。但是默认的ScrollBar,然后用他的存在来关闭它,所以它也定义了ScrollBar的样式。它将更改边距VerticalThumb,因此:
...
<!-- 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>
现在,主要组件正常显示。在 XAML 中声明 ComboBox:
<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>
仍然需要设置一个处理程序来调整Popup 的大小。我将使用函数FindChild<T> 在模板中使其成为搜索控件。为了安全起见,我会在ContentRendered 的Window 事件中执行此操作,以了解所有已加载的元素:
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);
}
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;
}
处理程序列表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;
}
}
原来如此:
Some notes: 要设置模板值,它们应该有一个默认值,否则该值将是NaN,我们不能设置它们。我们在这里设置了这些参数:
<Grid Name="DropDown" Width="100" Height="100" SnapsToDevicePixels="True">
模板和代码的完整列表可以在here 找到,因为它们的数量很大。样式不能轻易改变,因为它们是匆忙制作的,所以应该为自己做。
Part 2
至于存储输入的数据,这取决于您的目标。我认为你可以这样做:
- 创建一个列表(可能是
ObservableCollection)来存储项目。
- 成功输入元素后,例如 -
which he was found 在某些来源中,将其保存到您的列表中。
- 将此列表绑定到
ComboBox。
只需设置属性IsEditable= "True" 和IsTextSearchEnabled= "True" 即可在下拉列表中显示输入字符(如我的示例所示)。
因此,您将拥有一个列表,其中添加了元素,可以向用户显示。