Pergunta

Qual seria a melhor maneira de desenvolver uma caixa de texto que lembre o último x número de entradas que foram colocadas nela.Este é um aplicativo independente escrito em C#.

Foi útil?

Solução

@Ethan

Eu esqueci o fato de que você gostaria de salvar isso, então não era uma coisa apenas por sessão: P Mas sim, você está completamente correto.

Isso é feito facilmente, especialmente porque são apenas strings básicas, basta escrever o conteúdo de AutoCompleteCustomSource do TextBox em um arquivo de texto, em linhas separadas.

Eu tinha alguns minutos, então escrevi um exemplo de código completo... Eu teria feito antes, pois sempre tento mostrar o código, mas não tive tempo.De qualquer forma, aqui está tudo (menos o código do designer).

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

Este código funcionará exatamente como está, você só precisa criar a GUI com um TextBox chamado txtMain e conectar os eventos KeyDown, Closed e Load ao TextBox e ao formulário Main.

Observe também que, para este exemplo e para simplificar, optei apenas por detectar a tecla Enter sendo pressionada como meu gatilho para salvar a string na coleção.Provavelmente há mais/diferentes eventos que seriam melhores, dependendo de suas necessidades.

Além disso, o modelo usado para preencher a coleção não é muito "inteligente". Ele simplesmente exclui a corda mais antiga quando a coleção chega ao limite de 10.Provavelmente isso não é o ideal, mas funciona para o exemplo.Você provavelmente gostaria de algum tipo de sistema de classificação (especialmente se realmente quiser que seja semelhante ao Google)

Uma observação final: as sugestões aparecerão na ordem em que estão na coleção.Se por algum motivo você quiser que eles apareçam de forma diferente, basta classificar a lista como desejar.

Espero que ajude!

Outras dicas

Na verdade, isso é bastante fácil, especialmente em termos de mostrar a parte "AutoCompletar".Em termos de lembrar o último número x de entradas, você apenas terá que decidir sobre um evento (ou eventos) específico que você considera como uma entrada sendo concluída e anotar essa entrada em uma lista...um AutoCompleteStringCollection para ser mais preciso.

A classe TextBox possui as 3 propriedades a seguir que você precisará:

  • AutoCompleteCustomSource
  • Modo AutoCompletar
  • Fonte de preenchimento automático

Defina AutoCompleteMode como SuggestAppend e AutoCompleteSource como CustomSource.

Então, em tempo de execução, sempre que uma nova entrada for feita, use o método Add() de AutoCompleteStringCollection para adicionar essa entrada à lista (e retirar as antigas, se desejar).Na verdade, você pode fazer esta operação diretamente na propriedade AutoCompleteCustomSource do TextBox, desde que já a tenha inicializado.

Agora, toda vez que você digitar no TextBox ele irá sugerir entradas anteriores :)

Veja este artigo para um exemplo mais completo: http://www.c-sharpcorner.com/UploadFile/mahesh/AutoCompletion02012006113508AM/AutoCompletion.aspx

O AutoComplete também possui alguns recursos integrados, como FileSystem e URLs (embora faça apenas coisas que foram digitadas no IE...)

Eu armazeno a lista de conclusão no registro.

O código que uso está abaixo.É reutilizável, em três etapas:

  1. substitua o namespace e o nome da classe neste código pelo que você usar.
  2. Chame FillFormFromRegistry() no formulário Carregar evento e chame SaveFormToRegistry no Fechando evento.
  3. compile isso em seu projeto.

Você precisa decorar a montagem com dois atributos: [assembly: AssemblyProduct("...")] e [assembly: AssemblyCompany("...")] .(Esses atributos normalmente são definidos automaticamente em projetos criados no Visual Studio, portanto, não considero isso uma etapa.)

Gerenciar o estado desta forma é totalmente automático e transparente para o usuário.

Você pode usar o mesmo padrão para armazenar qualquer tipo de estado para seu aplicativo WPF ou WinForms.Como o estado das caixas de texto, caixas de seleção e menus suspensos.Também você pode armazenar/restaurar o tamanho da janela - muito útil - na próxima vez que o usuário executar o aplicativo, ele abrirá no mesmo lugar e com o mesmo tamanho de quando o fechou.Você pode armazenar o número de vezes que um aplicativo foi executado.Muitas possibilidades.

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

Algumas pessoas evite usar o Registro para armazenar estado, mas acho que é muito fácil e conveniente.Se desejar, você pode facilmente criar um instalador que remova todas as chaves de registro na desinstalação.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top