2013-07-11 19 views
15

muszę stworzyć combo-box, którecombo-box dostarczając listę zakończenia skalowalny nazwę pliku i listy rozwijanej z historią

  • zapewnia zmienny rozmiar listy uzupełnianie nazw plików i
  • utrzymuje Historia poprzednich wejść i pokazuje je w rozwijanej liście

podobne do okna dialogowego "Uruchom" w systemie Windows.

Resizable Zakończenie Lista:

file name completion

listy rozwijanej:

drop-down list

Czy istnieją odpowiednie kontrole gotowy w WinForms, WPF, lub w jakikolwiek otwarty - biblioteki źródłowe? Lub muszę wdrożyć go ręcznie przy użyciu kontroli niskiego poziomu?

Z góry dziękuję!

+0

lista budowy jest skalowalny tylko Windows 8. – Vladimir

Odpowiedz

8

rozwiązanie dla WPF

Part 1

Zasada, można użyć stylów i szablonów do realizacji Twojego pytania. W ComboBox wynik jest podany w Popup, ale domyślnie nie obsługuje zmiany rozmiaru. Dodaj zmianę rozmiaru nie jest trudne, jeśli używasz zdarzenia DragDelta. Przykład:

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; 
    } 
} 

Impreza jest lepiej ustawiony na kontrolę Thumb (Ma również wydarzenia DragStarted, DragCompleted).

Wszystko jest bardzo dobrze, ale musimy zrobić wewnątrz ComboBox. Jednym ze sposobów jest użycie Style i Template. Aby rozpocząć, dodaj Thumb w stylu ComboBox więc wydaje się w rozszerzonej listy:

... 

<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> 
...    

do normalnego wyświetlania Thumb, dodać do tego stylu z 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> 

Teraz, na tym etapie, pokazaliśmy ResizeGrip w rozwiniętej liście. Ale domyślna ScrollBar, a następnie zamyka go swoją obecnością, dlatego też definiuje styl dla ScrollBar. Spowoduje to zmianę marginesu VerticalThumb, a więc:

... 

<!-- 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>   

Teraz jest normalny wyświetlacz z głównych składników.Deklarowana ComboBox w 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> 

Pozostaje ustawić obsługi do zmiany rozmiaru Popup. Zrobię kontrolę wyszukiwania w szablonie za pomocą funkcji FindChild<T>. Pewności, zrobię to w przypadku ContentRendered z Window, aby wiedzieć, że wszystkie elementy ładowane:

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); 
} 

Notowania 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; 
    } 

Notowania obsługi 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; 
    } 
}  

Tak:

enter image description here

Some notes: Aby ustawić wartości szablonów, powinny one mieć wartość domyślną lub wartość będzie wynosić NaN, a my nie możemy ich ustawić. Mamy te parametry są ustawione tutaj:

<Grid Name="DropDown" Width="100" Height="100" SnapsToDevicePixels="True">  

Pełną listę szablonów i kodu można znaleźć here, ponieważ są one w dużej objętości. Style nie mogą być łatwo zmienione, ponieważ zostały wykonane w pośpiechu, więc powinny zrobić dla siebie.

Part 2

chodzi o zapamiętanie wprowadzonych danych, to zależy od Twoich celów. Myślę, że możesz zrobić coś takiego:

  1. Utwórz listę (może być ObservableCollection) do przechowywania przedmiotów.
  2. Po pomyślnym wprowadzeniu elementu, na przykład - which he was found w niektórych źródłach, zapisz go na liście.
  3. Wiązanie tej listy w ComboBox.

Wystarczy ustawić właściwości IsEditable= "True" i IsTextSearchEnabled= "True" aby wyświetlić znak wejściowy z listy rozwijanej (jak w moim przykładzie).

W ten sposób otrzymasz listę, w której dodawane są elementy, które mogą być pokazywane użytkownikowi.

1

Dla WindowsForms należy określić właściwości combosów AutoCompleteSource = AutoCompleteSource.FileSystem i (opcjonalnie) AutoCompleteMode = AutoCompleteMode.Suggest. Jego "udostępnia listę uzupełniania nazw plików".

Nie znam wbudowanego rozwiązania dla "przechowywania historii poprzednich danych wejściowych i wyświetlania ich na liście rozwijanej".

1

Oto kawałek wielokrotnego użycia kodu, które mogą Ci zacząć, oto jak go używać w standardowej aplikacji Windows, który ma standardową tekstowym na nim formach:

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(); 
     } 
    } 
} 

A oto kod:

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); 
     } 
    } 
} 

Uwaga: jest to fragment z tym 100% wolnego użyteczności składnika: CodeFluent Runtime Client