15

コンボボックスを作成する必要があります

  • サイズ変更可能なファイル名補完リストを提供し、
  • 以前の入力の履歴を保持し、ドロップダウン リストに表示します

Windowsの [実行] ダイアログに似ています。

サイズ変更可能な補完リスト:

ファイル名補完

ドロップダウンリスト:

ドロップダウンリスト

WinForms、WPF、またはオープンソース ライブラリに適切なコントロールが用意されていますか? または、低レベルのコントロールを使用して手動で実装する必要がありますか?

前もって感謝します!

4

3 に答える 3

8

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(彼にはイベントもありますDragStartedDragCompleted)。

それはすべて非常にうまくいっていますが、内部で行う必要があります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の は、彼の存在でそれを閉じるため、 のスタイルも定義しますScrollBarVerticalThumbしたがって、 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>        

これで、主要コンポーネントが通常どおり表示されます。ComboBoxXAML で宣言:

<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

入力したデータの保存に関しては、目的によって異なります。次のようなことができると思います:

  1. ObservableCollectionアイテムを保存するためのリスト ( の場合もあります) を作成します。
  2. たとえばwhich he was found、一部のソースで要素を正常に入力したら、それをリストに保存します。
  3. でこのリストをバインドしComboBoxます。

プロパティを設定し、入力文字をドロップダウン リストに表示するだけです (私の例のように)。IsEditable= "True"IsTextSearchEnabled= "True"

したがって、要素が追加されたリストが作成され、ユーザーに表示できます。

于 2013-07-12T07:53:19.400 に答える
1

これは、再利用可能なコードの一部であり、標準のテキスト ボックスを含む標準の 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

于 2013-07-14T09:39:48.940 に答える