开发一个文本框的最佳方法是记住最后输入的 x 个条目。这是一个用 C# 编写的独立应用程序。
3 回答
这实际上相当容易,尤其是在显示其中的“自动完成”部分方面。就记住最后 x 个条目而言,您只需要决定您认为已完成的条目的特定事件(或多个事件)并将该条目写入列表... AutoCompleteStringCollection 将精确的。
TextBox 类具有您需要的以下 3 个属性:
- 自动完成自定义源
- 自动完成模式
- 自动完成源
将 AutoCompleteMode 设置为 SuggestAppend,将 AutoCompleteSource 设置为 CustomSource。
然后在运行时,每次创建新条目时,使用 AutoCompleteStringCollection 的 Add() 方法将该条目添加到列表中(如果需要,可以弹出任何旧条目)。您实际上可以直接在 TextBox 的 AutoCompleteCustomSource 属性上执行此操作,只要您已经对其进行了初始化。
现在,每次您在 TextBox 中输入时,它都会建议以前的条目 :)
有关更完整的示例,请参阅本文:http ://www.c-sharpcorner.com/UploadFile/mahesh/AutoCompletion02012006113508AM/AutoCompletion.aspx
AutoComplete 还具有一些内置功能,例如 FileSystem 和 URL(尽管它只执行输入到 IE 中的内容......)
我忘记了你想要保存它的事实,所以它不是每个会话唯一的事情:P 但是,是的,你是完全正确的。
这很容易完成,特别是因为它只是基本字符串,只需将 AutoCompleteCustomSource 的内容从 TextBox 写到文本文件中的单独行。
我有几分钟的时间,所以我写了一个完整的代码示例……我以前会这样做,因为我总是尝试显示代码,但没有时间。无论如何,这就是全部内容(减去设计器代码)。
namespace AutoComplete
{
public partial class Main : Form
{
//so you don't have to address "txtMain.AutoCompleteCustomSource" every time
AutoCompleteStringCollection acsc;
public Main()
{
InitializeComponent();
//Set to use a Custom source
txtMain.AutoCompleteSource = AutoCompleteSource.CustomSource;
//Set to show drop down *and* append current suggestion to end
txtMain.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
//Init string collection.
acsc = new AutoCompleteStringCollection();
//Set txtMain's AutoComplete Source to acsc
txtMain.AutoCompleteCustomSource = acsc;
}
private void txtMain_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
//Only keep 10 AutoComplete strings
if (acsc.Count < 10)
{
//Add to collection
acsc.Add(txtMain.Text);
}
else
{
//remove oldest
acsc.RemoveAt(0);
//Add to collection
acsc.Add(txtMain.Text);
}
}
}
private void Main_FormClosed(object sender, FormClosedEventArgs e)
{
//open stream to AutoComplete save file
StreamWriter sw = new StreamWriter("AutoComplete.acs");
//Write AutoCompleteStringCollection to stream
foreach (string s in acsc)
sw.WriteLine(s);
//Flush to file
sw.Flush();
//Clean up
sw.Close();
sw.Dispose();
}
private void Main_Load(object sender, EventArgs e)
{
//open stream to AutoComplete save file
StreamReader sr = new StreamReader("AutoComplete.acs");
//initial read
string line = sr.ReadLine();
//loop until end
while (line != null)
{
//add to AutoCompleteStringCollection
acsc.Add(line);
//read again
line = sr.ReadLine();
}
//Clean up
sr.Close();
sr.Dispose();
}
}
}
此代码将完全按原样工作,您只需使用名为 txtMain 的 TextBox 创建 GUI,并将 KeyDown、Closed 和 Load 事件连接到 TextBox 和 Main 窗体。
还要注意,对于这个例子,为了简单起见,我只是选择检测被按下的 Enter 键作为我的触发器,以将字符串保存到集合中。根据您的需要,可能会有更多/不同的事件会更好。
此外,用于填充集合的模型不是很“智能”。当集合达到 10 的限制时,它只是删除最旧的字符串。这可能并不理想,但适用于示例。您可能需要某种评分系统(特别是如果您真的希望它是 Google 式的)
最后一点,这些建议实际上会按照它们在集合中的顺序显示。如果出于某种原因您希望它们以不同的方式显示,只需按您喜欢的方式对列表进行排序。
希望有帮助!
我将完成列表存储在注册表中。
我使用的代码如下。它是可重复使用的,分三个步骤:
- 用您使用的任何内容替换此代码中的命名空间和类名。
- 在 Form 的Load事件上调用 FillFormFromRegistry(),在Closing事件 上调用 SaveFormToRegistry 。
- 将其编译到您的项目中。
您需要使用两个属性来装饰程序集:[assembly: AssemblyProduct("...")]
和[assembly: AssemblyCompany("...")]
. (这些属性通常在 Visual Studio 中创建的项目中自动设置,因此我不将其视为一个步骤。)
以这种方式管理状态对用户来说是完全自动和透明的。
您可以使用相同的模式为您的 WPF 或 WinForms 应用程序存储任何类型的状态。像文本框、复选框、下拉菜单的状态。您还可以存储/恢复窗口的大小- 非常方便 - 下次用户运行应用程序时,它会在相同的位置以相同的大小打开,就像他们关闭它时一样。您可以存储应用程序运行的次数。很多可能性。
namespace Ionic.ExampleCode
{
public partial class NameOfYourForm
{
private void SaveFormToRegistry()
{
if (AppCuKey != null)
{
// the completion list
var converted = _completions.ToList().ConvertAll(x => x.XmlEscapeIexcl());
string completionString = String.Join("¡", converted.ToArray());
AppCuKey.SetValue(_rvn_Completions, completionString);
}
}
private void FillFormFromRegistry()
{
if (!stateLoaded)
{
if (AppCuKey != null)
{
// get the MRU list of .... whatever
_completions = new System.Windows.Forms.AutoCompleteStringCollection();
string c = (string)AppCuKey.GetValue(_rvn_Completions, "");
if (!String.IsNullOrEmpty(c))
{
string[] items = c.Split('¡');
if (items != null && items.Length > 0)
{
//_completions.AddRange(items);
foreach (string item in items)
_completions.Add(item.XmlUnescapeIexcl());
}
}
// Can also store/retrieve items in the registry for
// - textbox contents
// - checkbox state
// - splitter state
// - and so on
//
stateLoaded = true;
}
}
}
private Microsoft.Win32.RegistryKey AppCuKey
{
get
{
if (_appCuKey == null)
{
_appCuKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(AppRegistryPath, true);
if (_appCuKey == null)
_appCuKey = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(AppRegistryPath);
}
return _appCuKey;
}
set { _appCuKey = null; }
}
private string _appRegistryPath;
private string AppRegistryPath
{
get
{
if (_appRegistryPath == null)
{
// Use a registry path that depends on the assembly attributes,
// that are presumed to be elsewhere. Example:
//
// [assembly: AssemblyCompany("Dino Chiesa")]
// [assembly: AssemblyProduct("XPathVisualizer")]
var a = System.Reflection.Assembly.GetExecutingAssembly();
object[] attr = a.GetCustomAttributes(typeof(System.Reflection.AssemblyProductAttribute), true);
var p = attr[0] as System.Reflection.AssemblyProductAttribute;
attr = a.GetCustomAttributes(typeof(System.Reflection.AssemblyCompanyAttribute), true);
var c = attr[0] as System.Reflection.AssemblyCompanyAttribute;
_appRegistryPath = String.Format("Software\\{0}\\{1}",
p.Product, c.Company);
}
return _appRegistryPath;
}
}
private Microsoft.Win32.RegistryKey _appCuKey;
private string _rvn_Completions = "Completions";
private readonly int _MaxMruListSize = 14;
private System.Windows.Forms.AutoCompleteStringCollection _completions;
private bool stateLoaded;
}
public static class Extensions
{
public static string XmlEscapeIexcl(this String s)
{
while (s.Contains("¡"))
{
s = s.Replace("¡", "¡");
}
return s;
}
public static string XmlUnescapeIexcl(this String s)
{
while (s.Contains("¡"))
{
s = s.Replace("¡", "¡");
}
return s;
}
public static List<String> ToList(this System.Windows.Forms.AutoCompleteStringCollection coll)
{
var list = new List<String>();
foreach (string item in coll)
{
list.Add(item);
}
return list;
}
}
}
有些人回避使用注册表来存储状态,但我发现它真的很容易和方便。如果您愿意,您可以非常轻松地构建一个安装程序,在卸载时删除所有注册表项。