5

开发一个文本框的最佳方法是记住最后输入的 x 个条目。这是一个用 C# 编写的独立应用程序。

4

3 回答 3

6

这实际上相当容易,尤其是在显示其中的“自动完成”部分方面。就记住最后 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 中的内容......)

于 2008-09-04T01:29:21.983 回答
3

@Ethan

我忘记了你想要保存它的事实,所以它不是每个会话唯一的事情: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 式的)

最后一点,这些建议实际上会按照它们在集合中的顺序显示。如果出于某种原因您希望它们以不同的方式显示,只需按您喜欢的方式对列表进行排序。

希望有帮助!

于 2008-09-05T01:17:21.957 回答
1

我将完成列表存储在注册表中。

我使用的代码如下。它是可重复使用的,分三个步骤:

  1. 用您使用的任何内容替换此代码中的命名空间和类名。
  2. 在 Form 的Load事件上调用 FillFormFromRegistry(),在Closing事件 上调用 SaveFormToRegistry 。
  3. 将其编译到您的项目中。

您需要使用两个属性来装饰程序集:[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("¡", "&#161;");
            }
            return s;
        }
        public static string XmlUnescapeIexcl(this String s)
        {
            while (s.Contains("&#161;"))
            {
                s = s.Replace("&#161;", "¡");
            }
            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;
        }
    }
}

有些人回避使用注册表来存储状态,但我发现它真的很容易和方便。如果您愿意,您可以非常轻松地构建一个安装程序,在卸载时删除所有注册表项。

于 2009-09-17T22:31:14.243 回答