在c#windoes App中使Facebook自动完成像文本框一样 [英] Making Facebook Autocomplete like textbox in c# windoes App
本文介绍了在c#windoes App中使Facebook自动完成像文本框一样的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
i想要创建一个winform文本框控件,就像Facebook自动完成文本框一样,这可以在网络应用程序的网络上找到,但我需要它在Windows中。
任何人都可以帮助我吗?
谢谢,
Mahesh
Hi,
i want to create a winform textbox control which works like a Facebook Autocomplete Textbox, this is available on net for web apps, but i need it in windows.
Can anyone help me ?
Thanks,
Mahesh
推荐答案
请查看以下链接
1) http://www.dotnetfunda.com/articles/article225 .aspx
2)在Windows中自动填充文本框c# [ ^ ]
让我知道是否需要任何帮助!!!
谢谢,>
Akash Detroja
please check following link
1) http://www.dotnetfunda.com/articles/article225.aspx
2) Autocomplete textbox in windows c#[^]
Let me Know if need any help!!!
Thanks,
Akash Detroja
我使用devcomponents文本框作为Base,但它还有一个winform tekst框以及
I'm using the devcomponents textbox as Base but it shoul with a winform tekst box as well
namespace Controls
{
using System;
using System.Collections; // if you would like to use ArrayList insted
using System.Collections.Generic; // here we use Generic Type List<string>
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
public class autoCompleteLikeTextBoxX : DevComponents.DotNetBar.Controls.TextBoxX
{
#region Fields
// the ListBox used for suggestions
private System.Windows.Forms.ListBox myListBox;
// string to remember a former input
private string oldText;
// a Panel for displaying
private Panel panel;
// max items for the "dropdown listbox/panel" like a combobox.
private int _maxDropDownItems = 16;
// Stores the height if the maximum number of items is used
// used to check if there's enough room uder or above the control
private int _maxHeight = 100;
#endregion Fields
#region Constructors
// the constructor
public autoCompleteLikeTextBoxX()
: base()
{
// assigning some default values
// minimum characters to be typed before suggestions are displayed
this.MinTypedCharacters = 2;
// not cases sensitive
this.CaseSensitive = false;
this.AccentSensitive = false;
// the list for our suggestions database
// the sample dictionary en-EN.dic is stored here when form1 is loaded (see form1.Load event)
this.AutoCompleteList = new List<string>();
// the listbox used for suggestions
this.myListBox = new ListBox();
this.myListBox.Name = "SuggestionListBox";
this.myListBox.Font = this.Font;
this.myListBox.Visible = true;
this.MaxDropDownItems = 16;
this.RowHeight = getStringHeight("H");
// the panel to hold the listbox later on
this.panel = new Panel();
this.panel.Visible = false;
// At this moment the designer font isn't set, this is now done at the first time the control get's focus.
// this.panel.Font = this.Font;
// to be able to fit to changing sizes of the parent form
this.panel.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
// initialize with minimum size to avoid overlaping or flickering problems
this.panel.ClientSize = new System.Drawing.Size(1, 1);
this.panel.Name = "SuggestionPanel";
this.panel.Padding = new System.Windows.Forms.Padding(0, 0, 0, 0);
this.panel.Margin = new System.Windows.Forms.Padding(0, 0, 0, 0);
this.panel.BackColor = Color.Transparent;
this.panel.ForeColor = Color.Transparent;
this.panel.Text = "";
this.panel.PerformLayout();
// add the listbox to the panel if not already done
if (!panel.Controls.Contains(myListBox))
{
this.panel.Controls.Add(myListBox);
}
// make the listbox fill the panel
this.myListBox.Dock = DockStyle.Fill;
// only one itme can be selected from the listbox
this.myListBox.SelectionMode = SelectionMode.One;
// the events to be fired if an item is selected
this.myListBox.KeyDown += new KeyEventHandler(listBox_KeyDown);
this.myListBox.MouseClick += new MouseEventHandler(listBox_MouseClick);
this.myListBox.MouseDoubleClick += new MouseEventHandler(listBox_MouseDoubleClick);
this.myListBox.Leave += new EventHandler(listBox_Leave);
#region Excursus: ArrayList vs. List<string>
// surpringly ArrayList is a little faster than List<string>
// to use ArrayList instead, replace every 'List<string>' with 'ArrayList'
// i will used List<string> cause it's generic type
#endregion Excursus: ArrayList vs. List<string>
// the list of suggestions actually displayed in the listbox
// a subset of AutoCompleteList according to the typed in keyphrase
this.CurrentAutoCompleteList = new List<string>();
#region Excursus: DataSource vs. AddRange
// using DataSource is faster than adding items (see
// uncommented listBox.Items.AddRange method below)
#endregion Excursus: DataSource vs. AddRange
// Bind the CurrentAutoCompleteList as DataSource to the listbox
myListBox.DataSource = CurrentAutoCompleteList;
// set the input to remember, which is empty so far
oldText = this.Text;
}
#endregion Constructors
#region Properties
// maximumNumber of items to show (default = 16)
[CategoryAttribute("Behavior")]
public int MaxDropDownItems
{
get
{
return _maxDropDownItems;
}
set
{
_maxDropDownItems = value;
calculateMaxPanelHeight();
}
}
private int RowHeight
{
get;
set;
}
// the list for our suggestions database
public List<string> AutoCompleteList
{
get;
set;
}
// case sensitivity
[CategoryAttribute("Behavior")]
public bool CaseSensitive
{
get;
set;
}
[CategoryAttribute("Behavior")]
public bool AccentSensitive
{
get;
set;
}
// minimum characters to be typed before suggestions are displayed
[CategoryAttribute("Behavior")]
public int MinTypedCharacters
{
get;
set;
}
// the index selected in the listbox
// maybe of intrest for other classes
[Browsable(false)]
public int SelectedIndex
{
get
{
return myListBox.SelectedIndex;
}
set
{
// musn't be null
if (myListBox.Items.Count != 0)
{ myListBox.SelectedIndex = value; }
}
}
// the actual list of currently displayed suggestions
private List<string> CurrentAutoCompleteList
{
set;
get;
}
// the parent Form of this control
private Form ParentForm
{
get { return this.Parent.FindForm(); }
}
#endregion Properties
#region Methods
public void calculateMaxPanelHeight()
{
if (_maxDropDownItems > 0)
{
// one element extra beacuse the typed value can be present as well.
string measureString = "H\n";
Graphics e = this.myListBox.CreateGraphics();
for (int counter = 1; counter < _maxDropDownItems; counter++)
{
measureString += "H\n";
}
_maxHeight = getStringHeight(measureString);
}
else
{
_maxHeight = 0;
}
}
private int getStringHeight(string measureString)
{
Graphics e = this.myListBox.CreateGraphics();
Font stringFont = this.Font;
// Measure string.
SizeF stringSize = new SizeF();
stringSize = e.MeasureString(measureString, stringFont);
e.Dispose();
return (int)stringSize.Height;
}
// hides the listbox
public void HideSuggestionListBox()
{
if ((ParentForm != null))
{
// hiding the panel also hides the listbox
panel.Hide();
// now remove it from the ParentForm (Form1 in this example)
if (this.ParentForm.Controls.Contains(panel))
{
this.ParentForm.Controls.Remove(panel);
}
}
}
// Some stuff needs the parent form to be initiated
private bool _handlersSet;
protected override void OnEnter(EventArgs e)
{
base.OnEnter(e);
if (!_handlersSet)
{
this.myListBox.Font = this.Font;
// handles resizing the form at the staty of a resize the panel will be hidden en is shows again after the resize
this.ParentForm.ResizeBegin += new EventHandler(startResize);
this.ParentForm.ResizeEnd += new EventHandler(endResize);
_handlersSet = true;
_selectOnLeave = false;
}
}
/// <summary>
/// indicates if the item must be selected on leaving the control
/// </summary>
private bool _selectOnLeave;
protected override void OnKeyDown(KeyEventArgs args)
{
// if user presses key.up
if ((args.KeyCode == Keys.Up))
{
// move the selection in listbox one up
MoveSelectionInListBox((SelectedIndex - 1));
_selectOnLeave = true;
// work is done
args.Handled = true;
}
// on key.down
else if ((args.KeyCode == Keys.Down))
{
//move one down
MoveSelectionInListBox((SelectedIndex + 1));
_selectOnLeave = true;
args.Handled = true;
}
else if ((args.KeyCode == Keys.PageUp))
{
//move 10 up
MoveSelectionInListBox((SelectedIndex - 10));
_selectOnLeave = true;
args.Handled = true;
}
else if ((args.KeyCode == Keys.PageDown))
{
//move 10 down
MoveSelectionInListBox((SelectedIndex + 10));
_selectOnLeave = true;
args.Handled = true;
}
// on enter
else if ((args.KeyCode == Keys.Enter))
{
// select the item in the ListBox
_selectOnLeave = true;
SelectItem();
args.Handled = true;
}
else
{
// work is not done, maybe the base class will process the event, so call it...
base.OnKeyDown(args);
}
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
if (keyData == Keys.Tab)
{
SelectItem();
}
else if (keyData == Keys.Enter)
{
SelectItem();
}
else if (keyData == (Keys.Tab | Keys.ShiftKey) | keyData == (Keys.Tab | Keys.Shift) | keyData == (Keys.Tab | Keys.LShiftKey) | keyData == (Keys.Tab | Keys.RShiftKey))
{
SelectItem();
}
else if (keyData == (Keys.Enter | Keys.ShiftKey) | keyData == (Keys.Enter | Keys.Shift) | keyData == (Keys.Enter | Keys.LShiftKey) | keyData == (Keys.Enter | Keys.RShiftKey))
{
SelectItem();
}
return base.ProcessCmdKey(ref msg, keyData);
}
// if the user leaves the TextBox, the ListBox and the panel ist hidden
protected override void OnLostFocus(System.EventArgs e)
{
if (!panel.ContainsFocus)
{
// call the baseclass event
base.OnLostFocus(e);
// then hide the stuff
this.HideSuggestionListBox();
}
}
// if the input changes, call ShowSuggests()
protected override void OnTextChanged(EventArgs args)
{
// avoids crashing the designer
if (!this.DesignMode)
ShowSuggests();
base.OnTextChanged(args);
// remember input
oldText = this.Text;
}
// event for any key pressed in the ListBox
private void listBox_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
// on enter
if (e.KeyCode == Keys.Enter)
{
// select the current item
_selectOnLeave = true;
SelectItem();
// work done
e.Handled = true;
}
}
// event for MouseClick in the ListBox
private void listBox_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
{
// select the current item
_selectOnLeave = true;
SelectItem();
}
// event for DoubleClick in the ListBox
private void listBox_MouseDoubleClick(object sender, System.Windows.Forms.MouseEventArgs e)
{
// select the current item
_selectOnLeave = true;
SelectItem();
}
// event for DoubleClick in the ListBox
private void listBox_Leave(object sender, EventArgs e)
{
// select the current item
SelectItem();
}
private void MoveSelectionInListBox(int Index)
{
// beginning of list
if (Index <= -1)
{ this.SelectedIndex = 0; }
else
// end of liste
if (Index > (myListBox.Items.Count - 1))
{
SelectedIndex = (myListBox.Items.Count - 1);
}
else
// somewhere in the middle
{ SelectedIndex = Index; }
}
// selects the current item
private bool SelectItem()
{
// if the ListBox is not empty
if (((this.myListBox.Items.Count > 0) && (this.SelectedIndex > -1) && _selectOnLeave))
{
// set the Text of the TextBox to the selected item of the ListBox
// this.Text = this.listBox.SelectedItem.ToString();
this.Text = myListBox.GetItemText(myListBox.SelectedItem);
// and hide the ListBox
this.HideSuggestionListBox();
}
return true;
}
// shows the suggestions in ListBox beneath the TextBox
// and fitting it into the ParentForm
private void ShowSuggests()
{
// show only if MinTypedCharacters have been typed
if (this.Text.Length >= MinTypedCharacters)
{
// prevent overlapping problems with other controls
// while loading data there is nothing to draw, so suspend layout
panel.SuspendLayout();
// user is typing forward, char has been added at the end of the former input
if ((this.Text.Length > 0) && (this.oldText == this.Text.Substring(0, this.Text.Length - 1)))
{
//handle forward typing with refresh
UpdateCurrentAutoCompleteList();
}
// user is typing backward - char bas been removed
else if ((this.oldText.Length > 0) && (this.Text == this.oldText.Substring(0, this.oldText.Length - 1)))
{
//handle backward typing with refresh
UpdateCurrentAutoCompleteList();
}
// something within has changed
else
{
// handle other things like corrections in the middle of the input, clipboard pastes, etc. with refresh
UpdateCurrentAutoCompleteList();
}
if (((CurrentAutoCompleteList != null) && CurrentAutoCompleteList.Count > 0))
{
// finally show Panel and ListBox
// (but after refresh to prevent drawing empty rectangles)
panel.Show();
// at the top of all controls
panel.BringToFront();
// then give the focuse back to the TextBox (this control)
this.Focus();
}
// or hide if no results
else
{
this.HideSuggestionListBox();
}
// prevent overlapping problems with other controls
panel.ResumeLayout(true);
}
// hide if typed chars <= MinCharsTyped
else
{
this.HideSuggestionListBox();
}
}
// This is a timecritical part
// Fills/ refreshed the CurrentAutoCompleteList with appropreate candidates
private void UpdateCurrentAutoCompleteList()
{
// the list of suggestions has to be refreshed so clear it
CurrentAutoCompleteList.Clear();
// an find appropreate candidates for the new CurrentAutoCompleteList in AutoCompleteList
// be casesensitive
if (CaseSensitive)
{
if (AccentSensitive)
{
foreach (string Str in AutoCompleteList)
{
// search for the substring (equal to SQL Like Command)
if ((Str.IndexOf(this.Text, StringComparison.Ordinal) > -1))
// Add candidates to new CurrentAutoCompleteList
{ CurrentAutoCompleteList.Add(Str); }
}
}
else
{
foreach (string Str in AutoCompleteList)
{
// search for the substring (equal to SQL Like Command)
//if ((Str.IndexOf(this.Text, StringComparison.Ordinal) > -1))
if (new String(Str.Trim().Normalize(NormalizationForm.FormD).Where(c => c < 128).ToArray()).IndexOf(new string(this.Text.Trim().Normalize(NormalizationForm.FormD).Where(c => c < 128).ToArray())) > -1)
// Add candidates to new CurrentAutoCompleteList
{ CurrentAutoCompleteList.Add(Str); }
}
}
}
// or ignore case
else
{
if (AccentSensitive)
{
foreach (string Str in AutoCompleteList)
{
// and search for the substring (equal to SQL Like Command)
if ((Str.ToLowerInvariant().IndexOf(this.Text.ToLowerInvariant(), StringComparison.OrdinalIgnoreCase) > -1))
{ CurrentAutoCompleteList.Add(Str); }
}
}
else
{
foreach (string Str in AutoCompleteList)
{
if (new String(Str.Trim().Normalize(NormalizationForm.FormD).Where(c => c < 128).ToArray()).ToLowerInvariant().IndexOf(new string(this.Text.Trim().Normalize(NormalizationForm.FormD).Where(c => c < 128).ToArray()).ToLowerInvariant()) > -1)
{ CurrentAutoCompleteList.Add(Str); }
}
}
}
// countinue to update the ListBox - the visual part
UpdateListBoxItems();
}
// This is the most timecritical part, adding items to the ListBox
private void UpdateListBoxItems()
{
// if there is a ParentForm
if ((ParentForm != null))
{
// get its width
panel.Width = this.Width;
// calculate the remeining height beneath the TextBox
setPanelHeight(panel);
// and the Location to use
setPanelPosition(panel);
//panel.Location = this.Location + new Size(0, this.Height);
// Panel and ListBox have to be added to ParentForm.Controls before calling BingingContext
if (!this.ParentForm.Controls.Contains(panel))
{
// add the Panel and ListBox to the PartenForm
try
{
this.ParentForm.Controls.Add(panel);
}
catch (Exception ex) { }
}
// Update the listBox manually - List<string> dosn't support change events
// this is the DataSource approche, this is a bit tricky and may cause conflicts,
// so in case fall back to AddRange approache (see Excursus)
((CurrencyManager)myListBox.BindingContext[CurrentAutoCompleteList]).Refresh();
}
}
/// <summary>
/// Decides if the panel is placed below or above the textbox,
/// depanding on the available space on the form
/// </summary>
/// <param name="panel"></param>
private void setPanelPosition(Panel panel)
{
int availableBelow = 0; int availableAbove = 0;
Point P;
P = GetLocationRelativeToForm(this);
availableAbove = P.Y;
availableBelow += this.ParentForm.Height - P.Y - this.Height;
if (availableBelow > panel.Height)
{
panel.Location = P + new Size(0, this.Height);
}
else if (availableAbove > panel.Height)
{
panel.Location = new Point(P.X, P.Y - panel.Height + (int)((_maxDropDownItems - (panel.Height / RowHeight)) / 3));
}
else if (availableBelow > availableAbove)
{
panel.Height = availableBelow;
panel.Location = P + new Size(0, this.Height);
}
else
{
// a corection is needed
panel.Height = availableAbove;
panel.Location = new Point(P.X, P.Y - panel.Height + (int)((_maxDropDownItems - (panel.Height / RowHeight)) / 3));
}
}
// needed to determine where the panel will be placed and shown
private Point GetLocationRelativeToForm(Control c)
{
Point locationOnForm = c.FindForm().PointToClient(c.Parent.PointToScreen(c.Location));
return locationOnForm;
}
private void setPanelHeight(Panel pnl)
{
Point P;
int listHeight;
string currentList = "H\n";
int availableBelow = 0; int availableAbove = 0;
int AvailabelRows = 0;
// If the max rows are 0 or less the maximum space on the form will be used
if (_maxDropDownItems < 1)
{
P = GetLocationRelativeToForm(this);
availableAbove = P.Y;
availableBelow += this.ParentForm.Height - P.Y - this.Height;
if (availableBelow > availableAbove)
{
AvailabelRows = (int)availableBelow / RowHeight;
panel.Height = availableBelow;
}
else
{
AvailabelRows = (int)availableAbove / RowHeight;
panel.Height = availableAbove;
}
if (CurrentAutoCompleteList.Count < AvailabelRows)
{
for (int counter = 0; counter < CurrentAutoCompleteList.Count; counter += 1)
{
currentList += CurrentAutoCompleteList[counter] + "\n";
}
panel.Height = getStringHeight(currentList);
}
}
else if (CurrentAutoCompleteList.Count < _maxDropDownItems)
{
if (CurrentAutoCompleteList.Count > 0)
{
for (int counter = 0; counter < CurrentAutoCompleteList.Count; counter += 1)
{
currentList += CurrentAutoCompleteList[counter] + "\n";
}
listHeight = getStringHeight(currentList);
if (listHeight < _maxHeight && listHeight > 0)
{
panel.Height = listHeight;
}
else
{
panel.Height = 0;
}
}
}
else
{
panel.Height = _maxHeight;
}
}
#endregion Methods
#region Other
// Handle form resizing '
private bool resizing;
private void startResize(Object sender, EventArgs e)
{
if (panel.Visible)
{
resizing = true;
panel.Visible = false;
}
}
private void endResize(Object sender, EventArgs e)
{
if (resizing)
{
resizing = false;
panel.Width = this.Width;
setPanelHeight(panel);
setPanelPosition(panel);
panel.Visible = true;
}
}
//clean up the handlers at dispose.
public virtual void Dispose()
{
this.ParentForm.ResizeBegin -= new EventHandler(startResize);
this.ParentForm.ResizeEnd -= new EventHandler(endResize);
base.Dispose(true);
GC.SuppressFinalize(this);
}
#endregion Other
}
}
这篇关于在c#windoes App中使Facebook自动完成像文本框一样的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文