2014-01-06 5 views
0

У меня есть поле со списком внутри панели ToolStripControlHost, я знаю, что я, вероятно, не должен использовать классы, связанные с ToolStrip, за пределами ToolStrip, но я не мог найти никаких других ожиданий, чтобы сделать элемент управления накладывать другие элементы управления/окна. Проблема, которая у меня есть, заключается в том, что по мере добавления большего количества элементов в поле со списком она заканчивается все дальше и дальше вверх по экрану, в конце концов я заканчиваю тем, что поле со списком проходит от верхней части экрана до нижней части экран.Ограничить высоту поля со списком

То, что я хотел бы сделать, это иметь возможность расширяться вниз, но не вверх, если у него заканчивается комната, тогда она должна прокручиваться. Я попытался сделать это, обернув его в Panel с помощью AutoScroll = true. Я установить высоту панели каждый раз, когда элемент добавляется в поле со списком, как это:

var screenY = PointToScreen(_pnlListBoxContainer.Location).Y; 
var newBottom = _listBox.Height + screenY; 
if (newBottom > Screen.PrimaryScreen.Bounds.Height) 
{ 
    _pnlListBoxContainer.Height = Screen.PrimaryScreen.Bounds.Height - screenY; 
} 
else 
{ 
    _pnlListBoxContainer.Height = newBottom; 
} 
_pnlListBoxContainer.MaximumSize = _pnlListBoxContainer.Size; 

Я совершенно новым для WinForms и я не уверен, если это должно работать, или если есть лучше способ сделать это, в настоящее время он не работает. Что я делаю не так?

Спасибо,

Джо

P.S. Полный (очень грязный и взломал вместе) код здесь - извините:

public class AutoCompleteTextBox : TransparentTextboxWithBorder 
{ 
    private ToolStripDropDown _popupControl; 
    private ToolStripControlHost _controlHost; 
    private Panel _pnlListBoxContainer; 
    private ListBox _listBox; 
    private bool _isAdded; 
    private IAutoCompletable[] _values; 
    private String _formerValue = String.Empty; 
    public Font ListBoxFont 
    { 
     get { return _listBox.Font; } 
     set { _listBox.Font = value; } 
    } 

    public event AutoCompleteTextBoxItemSelectedEventHandler OnItemSelected; 

    public void ItemSelected() 
    { 
     InsertWord((String)_listBox.SelectedItem); 
     ResetListBox(); 
     _formerValue = this.Text; 
     if (OnItemSelected != null) 
     { 
      var item = Values.First(v => v.DisplayText == (string)_listBox.SelectedItem); 
      OnItemSelected(this, new AutoCompleteTextBoxItemSelectedEventArgs { SelectedItem = item }); 
     } 
    } 

    public AutoCompleteTextBox() 
    { 
     InitializeComponent(); 
     ResetListBox(); 

    } 

    private void InitializeComponent() 
    { 
     _listBox = new ListBox(); 
     _pnlListBoxContainer = new Panel { BackColor = Color.Red, Width = 100, Height = 400,AutoScroll = true}; 
     _pnlListBoxContainer.MinimumSize = _pnlListBoxContainer.Size; 
     _pnlListBoxContainer.Controls.Add(_listBox); 
     _popupControl = new ToolStripDropDown(); 
     _popupControl.Padding = new Padding(0); 
     _popupControl.Margin = new Padding(0); 
     _popupControl.AutoClose = false; // Focus bug - http://social.msdn.microsoft.com/Forums/windows/en-US/b8f9cf48-9bd4-4e8e-a9b7-bedc7491c619/toolstripcontrolhost-focus-problem?forum=winforms 
     _popupControl.AutoSize = true; 
     //_controlHost = new ToolStripControlHost(_listBox); 
     _controlHost = new ToolStripControlHost(_pnlListBoxContainer); 
     _controlHost.Padding = new Padding(0); 
     _controlHost.Margin = new Padding(0); 

     _popupControl.Items.Add(_controlHost); 
     _listBox.IntegralHeight = true; 
     _listBox.MouseDown += _listBox_Click; 
     this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.this_KeyDown); 
     this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.this_KeyUp); 
     this.LostFocus += AutoCompleteTextBox_LostFocus; 


     // Fixed by AutoClose = false above 
     // List box is now completly seperate so it needs its own key handlers 
     //_controlHost.KeyDown += new System.Windows.Forms.KeyEventHandler(this.this_KeyDown); 
     //_controlHost.KeyUp += (sender, args) => 
     //{ 
     // if (args.KeyCode == Keys.Tab) 
     // { 
     //  // For some reason the key down event doesnt fire for tab when in a controlhost so we just use key up 
     //  this_KeyDown(sender, args); 
     // } 
     // this_KeyUp(sender, args); 
     //}; 

    } 

    void AutoCompleteTextBox_LostFocus(object sender, EventArgs e) 
    { 
     // Firing close means that the selected index changed event doesn't fire so we delay it 
     var tmr = new Timer(); 
     tmr.Interval = 100; 
     tmr.Tick += (o, args) => 
     { 
      _popupControl.Close(); 
      tmr.Stop(); 
     }; 
     tmr.Start(); 
    } 

    void _listBox_Click(object sender, EventArgs e) 
    { 
     ItemSelected(); 
    } 

    private void ShowListBox() 
    { 
     if (!_isAdded) 
     { 
      //_listBox.Left = this.Left; 
      //_listBox.Top = this.Top + this.Height; 
      //_pnlListBoxContainer.Left = this.Left; 
      //_pnlListBoxContainer.Top = this.Top + this.Height; 
      _isAdded = true; 
     } 
     //_listBox.Visible = true; 
     //_listBox.BringToFront(); 
     _pnlListBoxContainer.Visible = true; 
     _pnlListBoxContainer.BringToFront(); 
     _popupControl.BackColor = Color.Green; 
     _popupControl.Show(this, CalculateDropPosition(), ToolStripDropDownDirection.BelowRight); 
    } 

    private Point CalculateDropPosition() 
    { 
     Point point = new Point(0, this.Height); 
     if ((this.PointToScreen(new Point(0, 0)).Y + this.Height + _controlHost.Height) > Screen.PrimaryScreen.WorkingArea.Height) 
     { 
      point.Y = -this._controlHost.Height - 7; 
     } 
     return point; 
    } 

    public void ResetListBox() 
    { 
     _popupControl.Close(); 
    } 

    public void Reset() 
    { 
     ResetListBox(); 
     _formerValue = string.Empty; 
     _oldMatchesHashCode = 0; 
    } 

    private void this_KeyUp(object sender, KeyEventArgs e) 
    { 
     UpdateListBox(); 
    } 

    private void this_KeyDown(object sender, KeyEventArgs e) 
    { 
     switch (e.KeyCode) 
     { 
      case Keys.Return: 
      case Keys.Tab: 
       { 
        if (_listBox.Visible) 
        { 
         ItemSelected(); 
        } 
        break; 
       } 
      case Keys.Down: 
       { 
        if ((_listBox.Visible) && (_listBox.SelectedIndex < _listBox.Items.Count - 1)) 
        { 
         _listBox.SelectedIndex++; 
        } 
        break; 
       } 
      case Keys.Up: 
       { 
        if ((_listBox.Visible) && (_listBox.SelectedIndex > 0)) 
        { 
         _listBox.SelectedIndex--; 
        } 
        break; 
       } 
     } 
    } 

    protected override bool IsInputKey(Keys keyData) 
    { 
     switch (keyData) 
     { 
      case Keys.Tab: 
       return true; 
      default: 
       return base.IsInputKey(keyData); 
     } 
    } 

    private int _oldMatchesHashCode = 0; 
    private void UpdateListBox() 
    { 
     if (this.Text != _formerValue) 
     { 
      _formerValue = this.Text; 
      String word = GetWord(); 

      if (word.Length > 0) 
      { 
       var matches = Array.FindAll(_values, 
        x => (x.Match(word) && !SelectedValues.Contains(x.DisplayText))); 
       int hashCode = 0; 
       foreach (var match in matches) 
       { 
        unchecked 
        { 
         hashCode += match.DisplayText.GetHashCode(); 
        } 
       } 
       if (hashCode == _oldMatchesHashCode) 
       { 
        return; 
       } 
       _oldMatchesHashCode = hashCode; 
       if (matches.Length > 0) 
       { 
        SuspendLayout(); 
        ShowListBox(); 
        _listBox.Items.Clear(); 
        Array.ForEach(matches, x => _listBox.Items.Add(x.DisplayText)); 
        _listBox.SelectedIndex = 0; 
        _listBox.Height = 0; 
        _listBox.Width = 0; 
        this.Focus(); 
        using (Graphics graphics = _listBox.CreateGraphics()) 
        { 
         for (int i = 0; i < _listBox.Items.Count; i++) 
         { 
          _listBox.Height += _listBox.GetItemHeight(i); 
          // it item width is larger than the current one 
          // set it to the new max item width 
          // GetItemRectangle does not work for me 
          // we add a little extra space by using '_' 
          int itemWidth = (int)graphics.MeasureString(((String)_listBox.Items[i]) + "_", _listBox.Font).Width; 
          _listBox.Width = (_listBox.Width < itemWidth) ? itemWidth : _listBox.Width; 
         } 
        } 

        if (_listBox.Width < 200) 
         _listBox.Width = 200; 
        _pnlListBoxContainer.Width = _listBox.Width; 

        var screenY = PointToScreen(_pnlListBoxContainer.Location).Y; 
        var newBottom = _listBox.Height + screenY; 
        if (newBottom > Screen.PrimaryScreen.Bounds.Height) 
        { 
         _pnlListBoxContainer.Height = Screen.PrimaryScreen.Bounds.Height - screenY; 
        } 
        else 
        { 
         _pnlListBoxContainer.Height = newBottom; 
        } 
        _pnlListBoxContainer.MaximumSize = _pnlListBoxContainer.Size; 

        ResumeLayout(); 
       } 
       else 
       { 
        ResetListBox(); 
       } 
      } 
      else 
      { 
       ResetListBox(); 
       _oldMatchesHashCode = 0; 
      } 
     } 
    } 

    private String GetWord() 
    { 
     String text = this.Text; 
     int pos = this.SelectionStart; 

     int posStart = text.LastIndexOf(';', (pos < 1) ? 0 : pos - 1); 
     posStart = (posStart == -1) ? 0 : posStart + 1; 
     int posEnd = text.IndexOf(';', pos); 
     posEnd = (posEnd == -1) ? text.Length : posEnd; 

     int length = ((posEnd - posStart) < 0) ? 0 : posEnd - posStart; 

     return text.Substring(posStart, length); 
    } 

    private void InsertWord(String newTag) 
    { 
     String text = this.Text; 
     int pos = this.SelectionStart; 

     int posStart = text.LastIndexOf(';', (pos < 1) ? 0 : pos - 1); 
     posStart = (posStart == -1) ? 0 : posStart + 1; 
     int posEnd = text.IndexOf(';', pos); 

     String firstPart = text.Substring(0, posStart) + newTag; 
     String updatedText = firstPart + ((posEnd == -1) ? "" : text.Substring(posEnd, text.Length - posEnd)); 


     this.Text = updatedText; 
     this.SelectionStart = firstPart.Length; 
    } 

    public IAutoCompletable[] Values 
    { 
     get 
     { 
      return _values; 
     } 
     set 
     { 
      _values = value; 
     } 
    } 

    public List<String> SelectedValues 
    { 
     get 
     { 
      String[] result = Text.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); 
      return new List<String>(result); 
     } 
    } 

} 
+0

Вы имеете в виду комбинированное поле, как в выпадающем меню, да? Если я правильно понимаю, вы добавляете в поле со списком достаточное количество элементов, которое заканчивается дольше, чем ваше окно при расширении? – Brandon

ответ

0

Я думаю, что я узнал, почему:

Выберите свой Combo Box, нажмите клавишу F4, чтобы открыть окно Свойства и установить DropDownHeight свойство должно быть 106 и установить MaxDropDownItems равным 8. Это значения по умолчанию для комбинированных ящиков.

Смежные вопросы