我需要创建一个组合框
- 提供可调整大小的文件名完成列表和
- 保留以前输入的历史记录并在下拉列表中显示它们
类似于Windows中的“运行”对话框。
可调整大小的完成列表:
下拉列表:
WinForms、WPF 或任何开源库中是否有合适的控件?或者我需要使用低级控件手动实现它?
先感谢您!
我需要创建一个组合框
类似于Windows中的“运行”对话框。
可调整大小的完成列表:
下拉列表:
WinForms、WPF 或任何开源库中是否有合适的控件?或者我需要使用低级控件手动实现它?
先感谢您!
WPF解决方案
Part 1
原则上,您可以使用样式和模板来实现您的问题。结果在ComboBox
中给出Popup
,但默认不支持更改大小。如果您使用 event ,添加调整大小并不困难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
and Template
。首先,添加一个Thumb
in 样式ComboBox
,使其出现在展开的列表中:
...
<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
。它将改变 margin 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>
现在,主要组件可以正常显示了。ComboBox
在 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>
仍然需要设置一个处理程序来调整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">
可以在此处找到完整的模板和代码列表,因为它们的数量很大。样式不能轻易改变,因为它们是匆忙制作的,所以应该为自己做。
Part 2
至于存储输入的数据,这取决于您的目标。我认为你可以这样做:
ObservableCollection
)来存储项目。which he was found
在某些来源中,将其保存到您的列表中。ComboBox
.只需设置属性并在下拉列表中显示输入字符(如我的示例所示)。IsEditable
= "True"
IsTextSearchEnabled
= "True"
因此,您将有一个列表,其中添加了元素,可以向用户显示。
对于 WindowsForms,您需要指定组合属性AutoCompleteSource = AutoCompleteSource.FileSystem 和(可选)AutoCompleteMode = AutoCompleteMode.Suggest。它“提供了一个可调整大小的文件名完成列表”。
我不知道“保留以前输入的历史并将它们显示在下拉列表中”的嵌入式解决方案。
这是一段可重用的代码,可以帮助您入门,这是您如何将其与具有标准文本框的标准 Windows 窗体应用程序一起使用:
public partial class Form1 : Form
{
private AutoCompletion _ac;
public Form1()
{
InitializeComponent();
// add the autocompletion tool to the 'textBox1' text box
_ac = new AutoCompletion(textBox1);
_ac.TextChanged += AutoCompletionTextChanged;
}
private void AutoCompletionTextChanged(object sender, EventArgs e)
{
if (ShowSomething())
{
// clear the items and add 50 as an example
_ac.Items.Clear();
for (int i = 0; i < 50; i++)
{
AutoCompletion.AutoCompletionItem item = new AutoCompletion.AutoCompletionItem();
item.Text = "Item " + i;
_ac.Items.Add(item);
}
_ac.SelectedItem = _ac.Items[0]; // pre-select first one as an example
_ac.Show(); // show the autocompletion window
return;
}
}
private bool ShowSomething()
{
return true; // TODO: implement this
}
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
// don't forget to dispose the tool
if (_ac != null)
{
_ac.Dispose();
}
}
}
这是代码:
public sealed class AutoCompletion: IDisposable
{
private AutoCompleteForm _form;
private AutoCompletionItem _selectedItem;
private readonly List<AutoCompletionItem> _items = new List<AutoCompletionItem>();
public event EventHandler TextChanged;
public AutoCompletion(TextBoxBase textBox)
{
if (textBox == null)
throw new ArgumentNullException("textBox");
_form = new AutoCompleteForm(this);
_form.SetOwner(textBox);
Margin = new Padding(2, 0, 30, 0);
ImageMargin = 2;
BorderStyle = FormBorderStyle.SizableToolWindow;
MinimumLines = 1;
MaximumLines = 100;
IsEnabled = true;
}
public bool IsEnabled
{
get
{
return _form.IsEnabled;
}
set
{
_form.IsEnabled = value;
}
}
public bool UserDismissed
{
get
{
return _form.UserDismissed;
}
set
{
_form.UserDismissed = value;
}
}
public AutoCompletionItem SelectedItem
{
get
{
return _selectedItem;
}
set
{
if (_selectedItem == value)
return;
_selectedItem = value;
}
}
public Font Font
{
get
{
return _form.ListBoxFont;
}
set
{
_form.ListBoxFont = value;
}
}
public int MinimumLines
{
get
{
return _form.MinimumLines;
}
set
{
_form.MinimumLines = value;
}
}
public int MaximumLines
{
get
{
return _form.MaximumLines;
}
set
{
_form.MaximumLines = value;
}
}
public int ImageMargin
{
get
{
return _form.ImageMargin;
}
set
{
_form.ImageMargin = value;
}
}
public Padding Margin
{
get
{
return _form.ListBoxMargin;
}
set
{
_form.ListBoxMargin = value;
}
}
public FormBorderStyle BorderStyle
{
get
{
return _form.FormBorderStyle;
}
set
{
_form.FormBorderStyle = value;
}
}
public ImageList Images
{
get
{
return _form.Images;
}
set
{
_form.Images = value;
}
}
public IList<AutoCompletionItem> Items
{
get
{
return _items;
}
}
public void Hide()
{
_form.HideList();
}
public void Show()
{
_form.ShowList();
}
public void Dispose()
{
if (_form != null)
{
_form.Dispose();
_form = null;
}
}
private void OnTextChanged(object sender, EventArgs e)
{
EventHandler handler = TextChanged;
if (handler != null)
{
handler(sender, e);
}
}
public class AutoCompletionItem
{
public AutoCompletionItem()
: this(null)
{
}
public AutoCompletionItem(string text)
: this(text, -1)
{
}
public AutoCompletionItem(string text, int imageIndex)
:this(text, null, imageIndex)
{
}
public AutoCompletionItem(string text, string toolTip, int imageIndex)
:this(text, toolTip, null, imageIndex)
{
}
public AutoCompletionItem(string text, string toolTip, string toolTipTitle, int imageIndex)
{
if (text == null)
{
text = string.Empty;
}
Text = text;
ToolTip = toolTip;
ImageIndex = imageIndex;
ToolTipTitle = toolTipTitle;
}
public string Text { get; set; }
public string ToolTip { get; set; }
public string ToolTipTitle { get; set; }
public int ImageIndex { get; set; }
}
private class AutoCompleteForm : Form
{
private readonly ImageListBox _listBox;
private TextBoxBase _textBox;
private bool _isEnabled;
private readonly AutoCompletion _autoCompletion;
[DllImport("user32.dll")]
private static extern bool PostMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam);
[DllImport("user32.dll")]
private static extern IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
[DllImport("user32.dll")]
private static extern int MsgWaitForMultipleObjectsEx(int nCount, IntPtr pHandles, int dwMilliseconds, int dwWakeMask, int dwFlags);
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
private const int GWL_HWNDPARENT = -8;
private const int WM_KEYDOWN = 0x0100;
private const int WM_KEYUP = 0x0101;
private const int WM_SIZING = 0x0214;
private const int WM_NCHITTEST = 0x0084;
private const int HTNOWHERE = 0;
private const int HTLEFT = 10;
private const int HTTOP = 12;
private const int HTTOPLEFT = 13;
private const int HTTOPRIGHT = 14;
private const int HTBOTTOMLEFT = 16;
private const int MWMO_INPUTAVAILABLE = 0x0004;
private class ImageListBox : ListBox
{
private ImageList _images;
private int _imageMargin;
private readonly AutoCompleteForm _form;
public readonly ToolTip _toolTip;
private Point _lastToolTipPoint;
public ImageListBox(AutoCompleteForm form)
{
_form = form;
BorderStyle = BorderStyle.None;
SelectionMode = SelectionMode.One;
DisplayMember = "Text";
Dock = DockStyle.Fill;
DrawMode = DrawMode.OwnerDrawFixed;
_toolTip = new ToolTip();
}
protected override void OnSelectedIndexChanged(EventArgs e)
{
base.OnSelectedIndexChanged(e);
if (SelectedIndices.Count == 0)
return;
Rectangle rect = GetItemRectangle(SelectedIndices[0]);
AutoCompletionItem item = (AutoCompletionItem)Items[SelectedIndices[0]];
_toolTip.Show(item.ToolTip, this, Width + 2 * _form.BorderSize.Width, rect.Top);
if (!string.IsNullOrEmpty(item.ToolTipTitle))
{
_toolTip.ToolTipTitle = item.ToolTipTitle;
}
_toolTip.ShowAlways = true;
}
protected override void OnDoubleClick(EventArgs e)
{
_form.Commit(null);
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
int index = IndexFromPoint(e.Location);
if ((index >= 0) && (index < Items.Count))
{
AutoCompletionItem item = (AutoCompletionItem)Items[index];
if (!string.IsNullOrEmpty(item.ToolTip))
{
// avoid flickering
if ((_toolTip.GetToolTip(this) != item.ToolTip) && (_lastToolTipPoint != e.Location))
{
_toolTip.SetToolTip(this, item.ToolTip);
if (!string.IsNullOrEmpty(item.ToolTipTitle))
{
_toolTip.ToolTipTitle = item.ToolTipTitle;
}
_lastToolTipPoint = e.Location;
}
}
}
}
protected override void WndProc(ref Message m)
{
// we need this to track the TAB character
if ((m.Msg == WM_KEYUP) && (m.WParam.ToInt32() == 9))
{
_form.OnTabPressed();
m.Result = new IntPtr(1); // handled
return;
}
base.WndProc(ref m);
}
public int ImageMargin
{
get
{
return _imageMargin;
}
set
{
if (_imageMargin == value)
return;
_imageMargin = value;
Invalidate();
}
}
public ImageList Images
{
get
{
return _images;
}
set
{
if (_images == value)
return;
_images = value;
if (_images != null)
{
ItemHeight = _images.ImageSize.Height + Margin.Vertical;
}
Invalidate();
}
}
protected override void OnDrawItem(DrawItemEventArgs e)
{
if (e.Index < 0)
return;
AutoCompletionItem item = (AutoCompletionItem)Items[e.Index];
if (_images == null)
{
e.DrawBackground();
e.DrawFocusRectangle();
using (Brush foreBrush = new SolidBrush(e.ForeColor))
{
e.Graphics.DrawString(item.Text, e.Font, foreBrush, e.Bounds);
}
return;
}
Rectangle bounds = e.Bounds;
bounds.X += Margin.Left;
if (item.ImageIndex >= 0)
{
_images.Draw(e.Graphics, bounds.Left, bounds.Top, item.ImageIndex);
bounds.X += _images.ImageSize.Width + _imageMargin;
}
using (Brush backBrush = new SolidBrush(e.BackColor))
{
e.Graphics.FillRectangle(backBrush, bounds);
}
if (((e.State & DrawItemState.Focus) == DrawItemState.Focus) && ((e.State & DrawItemState.NoFocusRect) != DrawItemState.NoFocusRect))
{
ControlPaint.DrawFocusRectangle(e.Graphics, bounds, ForeColor, BackColor);
}
bounds.Y += Margin.Top;
using (Brush foreBrush = new SolidBrush(e.ForeColor))
{
e.Graphics.DrawString(item.Text, e.Font, foreBrush, bounds);
}
}
}
public AutoCompleteForm(AutoCompletion autoCompletion)
{
_autoCompletion = autoCompletion;
ShowInTaskbar = false;
ControlBox = false;
MinimizeBox = false;
MaximizeBox = false;
Text = string.Empty;
AutoScaleMode = AutoScaleMode.None;
_listBox = new ImageListBox(this);
_listBox.KeyDown += OnListBoxKeyDown;
Controls.Add(_listBox);
DockPadding.All = 0;
}
public bool UserDismissed { get; set; }
public int MaximumLines { get; set; }
public int MinimumLines { get; set; }
public bool IsEnabled
{
get
{
return _isEnabled;
}
set
{
if (_isEnabled != value)
{
_isEnabled = value;
if (!_isEnabled)
{
HideList();
}
}
}
}
public Font ListBoxFont
{
get
{
return _listBox.Font;
}
set
{
_listBox.Font = value;
}
}
public Padding ListBoxMargin
{
get
{
return _listBox.Margin;
}
set
{
_listBox.Margin = value;
}
}
public int ImageMargin
{
get
{
return _listBox.ImageMargin;
}
set
{
_listBox.ImageMargin = value;
}
}
public ImageList Images
{
get
{
return _listBox.Images;
}
set
{
_listBox.Images = value;
}
}
private Size BorderSize
{
get
{
Size size = Size - ClientSize;
return new Size(size.Width / 2, size.Height / 2);
}
}
private void OnTabPressed()
{
Commit(null);
}
private static bool PassThru(KeyEventArgs e)
{
if (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down || e.KeyCode == Keys.PageUp || e.KeyCode == Keys.PageDown)
return false;
return true;
}
private void OnListBoxKeyDown(object sender, KeyEventArgs e)
{
switch (e.KeyCode)
{
case Keys.Escape:
UserDismissed = true;
HideList();
return;
case Keys.Return:
Commit(null);
return;
case Keys.OemPeriod:
case Keys.Decimal:
UserDismissed = false;
if (_listBox.SelectedItem == null)
{
// repost
PostMessage(_autoCompletion._form._textBox.Handle, WM_KEYDOWN, new IntPtr((int)e.KeyData), IntPtr.Zero);
return;
}
Commit(".");
return;
default:
if (e.KeyCode == Keys.Back)
{
CaptureOriginalText();
}
if (PassThru(e))
{
PostMessage(_autoCompletion._form._textBox.Handle, WM_KEYDOWN, new IntPtr((int)e.KeyData), IntPtr.Zero);
}
return;
}
}
private static Point GetSelectionPoint(TextBoxBase textBox)
{
using (Graphics graphics = Graphics.FromHwnd(textBox.Handle))
{
string text;
if (textBox.Text.Length == 0)
{
// use dummy text
text = "I";
}
else
{
text = textBox.Text.Substring(0, textBox.SelectionStart);
}
SizeF size = graphics.MeasureString(text, textBox.Font);
if (size.Width > textBox.Width)
{
size.Width = textBox.Width;
}
return textBox.Parent.PointToScreen(new Point((int)(size.Width + textBox.Location.X), (int)(size.Height + textBox.Location.Y)));
}
}
private bool _raiseTextChanged = true;
private void Commit(string extra)
{
UserDismissed = false;
if (_listBox.SelectedItem == null)
return;
_raiseTextChanged = false;
string newSelection = ((AutoCompletionItem)_listBox.SelectedItem).Text + extra;
string textBefore;
if (_originalSelectionStart > 0)
{
textBefore = _originalText.Substring(0, _originalSelectionStart);
int pos = textBefore.LastIndexOf('.');
if (pos >= 0)
{
textBefore = textBefore.Substring(0, pos);
}
else
{
textBefore = string.Empty;
}
}
else
{
textBefore = string.Empty;
}
if ((!textBefore.EndsWith(".")) && (!newSelection.EndsWith(".")) && (textBefore.Length > 0))
{
textBefore += ".";
}
_textBox.Text = textBefore + newSelection;// +textAfter;
_textBox.SelectionLength = 0;
_textBox.SelectionStart = _textBox.Text.Length;
_raiseTextChanged = true;
CaptureOriginalText();
HideList();
}
public void SetOwner(TextBoxBase textBox)
{
if (textBox == null)
throw new ArgumentNullException("textBox");
_textBox = textBox;
_textBox.KeyDown += OnTextBoxKeyDown;
_textBox.TextChanged += OnTextBoxTextChanged;
}
private void OnTextBoxTextChanged(object sender, EventArgs e)
{
if (!IsEnabled)
return;
if (!_raiseTextChanged)
return;
_autoCompletion.OnTextChanged(_textBox, e);
}
private void CaptureOriginalText()
{
_originalText = _textBox.Text;
_originalSelectionStart = _textBox.SelectionStart;
_originalSelectionLength = _textBox.SelectionLength;
}
private void OnTextBoxKeyDown(object sender, KeyEventArgs e)
{
if (!IsEnabled)
return;
if (Visible)
return;
CaptureOriginalText();
}
public void HideList()
{
Visible = false;
}
public void ShowList()
{
if (_autoCompletion.Items.Count == 0)
return;
if ((_textBox.Text.EndsWith(".")) && (!_originalText.EndsWith(".")))
{
_originalText += ".";
_originalSelectionStart++;
}
Visible = false;
_listBox.Items.Clear();
float maxWidth = 0;
int height = _autoCompletion.Items.Count * _listBox.ItemHeight;
using (Graphics graphics = Graphics.FromHwnd(_listBox.Handle))
{
foreach (AutoCompletionItem item in _autoCompletion._items)
{
int index = _listBox.Items.Add(item);
if (item == _autoCompletion.SelectedItem)
{
_listBox.SelectedIndex = index;
}
if (item.Text != null)
{
SizeF size = graphics.MeasureString(item.Text, _listBox.Font);
if (size.Width > maxWidth)
{
maxWidth = size.Width;
}
}
}
}
SetWindowLong(Handle, GWL_HWNDPARENT, _textBox.Handle);
Point point = GetSelectionPoint(_textBox);
Size borderSize = BorderSize;
if (Images != null)
{
point.X -= Images.ImageSize.Width;
}
point.X -= borderSize.Width + ListBoxMargin.Left + ImageMargin;
point.Y += 4; // TODO: can we be smarter?
Location = point;
int width = (int)maxWidth + ListBoxMargin.Right;
int minLines = MinimumLines;
if (minLines < 1)
{
minLines = 1;
}
int maxLines = MaximumLines;
if (maxLines < minLines)
{
maxLines = minLines;
}
height = Math.Min(height, maxLines * _listBox.ItemHeight);
ClientSize = new Size(width, height);
MinimumSize = new Size(width, minLines * _listBox.ItemHeight) + borderSize;
MaximumSize = new Size(width * 2, maxLines * _listBox.ItemHeight);
Visible = true;
_listBox.Focus();
DoModalLoop();
}
private string _originalText;
private int _originalSelectionStart;
private int _originalSelectionLength;
private void DoModalLoop()
{
while (Visible)
{
typeof(Application).InvokeMember("DoEventsModal", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, null);
MsgWaitForMultipleObjectsEx(0, IntPtr.Zero, 250, 0xff, MWMO_INPUTAVAILABLE);
}
}
protected override void OnDeactivate(EventArgs e)
{
base.OnDeactivate(e);
_listBox._toolTip.Hide(_listBox);
HideList();
}
protected override void WndProc(ref Message m)
{
// prevent resize handle on top & left of window
if (m.Msg == WM_NCHITTEST)
{
base.WndProc(ref m);
int ht = m.Result.ToInt32();
// if user hit left or top, pretend he didn't
if ((ht == HTLEFT) || (ht == HTBOTTOMLEFT) || (ht == HTTOP) || (ht == HTTOPLEFT) || (ht == HTTOPRIGHT))
{
m.Result = new IntPtr(HTNOWHERE);
}
return;
}
// ensure integral height and maximum size
if (m.Msg == WM_SIZING)
{
RECT rect = (RECT)Marshal.PtrToStructure(m.LParam, typeof(RECT));
int h = rect.Bottom - rect.Top;
int newh = h;
if ((h % _listBox.ItemHeight) != 0)
{
newh = ((h + _listBox.ItemHeight) / _listBox.ItemHeight) * _listBox.ItemHeight;
}
if (newh > (_listBox.ItemHeight * _listBox.Items.Count))
{
newh = _listBox.ItemHeight * (_listBox.Items.Count + 1);
}
rect.Bottom = rect.Top + newh;
Marshal.StructureToPtr(rect, m.LParam, false);
m.Result = new IntPtr(1); // handled
return;
}
base.WndProc(ref m);
}
}
}
注意:这是从这个 100% 免费的组件实用程序中摘录的:CodeFluent Runtime Client