コンボボックスを作成する必要があります
- サイズ変更可能なファイル名補完リストを提供し、
- 以前の入力の履歴を保持し、ドロップダウン リストに表示します
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
。1 つの方法は、 と を使用することStyle
ですTemplate
。まず、展開されたリストに表示されるようThumb
にスタイルを追加します。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
。VerticalThumb
したがって、 margin が変更されます。
...
<!-- 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"
したがって、要素が追加されたリストが作成され、ユーザーに表示できます。
これは、再利用可能なコードの一部であり、標準のテキスト ボックスを含む標準の 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