2013-07-11 32 views
15

tôi cần phải tạo ra một combo-box màMột hộp kết hợp cung cấp một danh sách hoàn thành tên tập tin thay đổi kích thước và danh sách thả xuống với một lịch sử

  • cung cấp một danh sách tên tập tin hoàn thành thay đổi kích thước và
  • giữ một lịch sử của các mục nhập trước đó và hiển thị chúng trong danh sách thả xuống

tương tự như hộp thoại "Chạy" trong Windows.

Resizable Danh sách hoàn thành:

file name completion

thả xuống liệt kê:

drop-down list

Có bất kỳ điều khiển phù hợp sẵn sàng trong WinForms, WPF, hoặc trong bất kỳ mở -thư viện nguồn? Hoặc tôi cần phải thực hiện nó bằng tay bằng cách sử dụng điều khiển cấp thấp?

Cảm ơn bạn trước!

+0

danh sách hoàn là thay đổi kích thước trong Windows 8 chỉ. – Vladimir

Trả lời

8

Giải pháp cho WPF

Part 1

Nguyên tắc, bạn có thể sử dụng phong cách và mẫu cho việc thực hiện các câu hỏi của bạn. Trong các ComboBox kết quả được đưa ra trong Popup, nhưng mặc định nó không hỗ trợ thay đổi kích thước. Thêm thay đổi kích thước không khó, nếu bạn sử dụng sự kiện DragDelta. Ví dụ:

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

Sự kiện này là tốt hơn để thiết lập trên Thumb điều khiển (Ông cũng có sự kiện DragStarted, DragCompleted).

Tất cả đều rất tốt, nhưng chúng tôi cần thực hiện bên trong ComboBox. Một cách là sử dụng StyleTemplate. Để bắt đầu, thêm một Thumb trong phong cách ComboBox để nó xuất hiện trong danh sách mở rộng:

... 

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

Đối với màn hình bình thường Thumb, thêm vào phong cách nó với một 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> 

Bây giờ, ở giai đoạn này, chúng tôi đã hiển thị ResizeGrip trong danh sách mở rộng. Tuy nhiên, mặc định ScrollBar, sau đó đóng nó với sự hiện diện của mình, vì vậy nó cũng xác định phong cách cho ScrollBar. Nó sẽ thay đổi lề VerticalThumb, do đó:

... 

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

Bây giờ, có một màn hình hiển thị bình thường của các thành phần chính.Tuyên bố ComboBox trong 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> 

Nó vẫn còn để thiết lập một handler cho thay đổi kích thước Popup. Tôi sẽ làm cho nó kiểm soát tìm kiếm trong mẫu bằng cách sử dụng hàm FindChild<T>. Để được an toàn, tôi sẽ làm điều đó trong trường hợp ContentRendered của Window, để biết rằng tất cả các yếu tố nạp:

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

Danh bạ nhà 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; 
    } 

Danh bạ nhà handler 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; 
    } 
}  

Nó như vậy:

enter image description here

Some notes: Để đặt giá trị mẫu, chúng phải có giá trị mặc định hoặc giá trị sẽ là NaN và chúng tôi không thể đặt chúng. Chúng tôi có những thông số được thiết lập ở đây:

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

Một danh sách đầy đủ các mẫu và mã có thể được tìm thấy here, vì chúng là lớn về khối lượng. Phong cách không thể dễ dàng thay đổi, bởi vì họ đã được thực hiện trong một vội vàng, vì vậy họ nên làm cho mình.

Part 2

Như để lưu trữ các dữ liệu nhập vào, nó phụ thuộc vào mục tiêu của mình. Tôi nghĩ bạn có thể làm một việc như sau:

  1. Tạo danh sách (có thể là ObservableCollection) để lưu trữ các mục.
  2. Sau khi nhập thành công phần tử, ví dụ: which he was found ở một số nguồn, hãy lưu nó vào danh sách của bạn.
  3. Gắn danh sách này vào ComboBox.

Chỉ cần thiết lập các thuộc tính IsEditable= "True"IsTextSearchEnabled= "True" để hiển thị các ký tự đầu vào trong danh sách thả xuống (như trong ví dụ của tôi).

Vì vậy, bạn sẽ có danh sách trong đó các thành phần được thêm vào, có thể được hiển thị cho người dùng.

1

Đối với WindowsForms, bạn cần chỉ định các thuộc tính combo AutoCompleteSource = AutoCompleteSource.FileSystem và (tùy chọn) AutoCompleteMode = AutoCompleteMode.Suggest. Của nó "cung cấp một danh sách hoàn thành tên tập tin thay đổi kích thước".

Tôi không biết giải pháp được nhúng cho "lưu giữ lịch sử các mục nhập trước đó và hiển thị chúng trong danh sách thả xuống".

1

Dưới đây là một đoạn mã tái sử dụng mà có thể giúp bạn bắt đầu, đây là cách bạn sử dụng nó với một chuẩn của Windows Forms ứng dụng mà có một Textbox tiêu chuẩn trên nó:

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

Và đây là đoạn code:

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

Lưu ý: đây là một đoạn trích từ tiện ích thành phần miễn phí 100% này: CodeFluent Runtime Client

Các vấn đề liên quan