none
WinForms ListView para WPF ListView RRS feed

  • Pergunta

  • Olá a todos, recentemente comecei a trabalhar com WPF, ainda estou sem muita entimidade, mas enfim.. Estou a fim de dar um upgrade no meu programa. O layout dele é simples, apenas um TabControl, e em cada item desse TabControl uma ListView com algumas colunas.

    O que estou a fim de fazer é basicamente o mesmo layout, porém usando XAML, e como ele nos da algumas vantagens, estou pensando em mudar algumas coisas, por exemplo, ao invez de usar apenas as Labels da ListView, colocar algumas TextBox na coluna "Name", que como vocês podem ver, é editável. A "grande mudança" não passa disso, a questão que eu tenho dúvida é, como preencher essa lista programaticamente? Sim, porque, eu vi que WPF nós usamos o Binding para mostrar informações na ListView, porém, isso é outra coisa que eu não estou muito intimo ainda. Até por que, no meu programa eu vou ter que "povoar" a lista programaticamente, as informações serão coletadas a partir de escolhas do usuário, então eu teria que colocar um conteúdo especifico nas TextBox que eu adicionaria nessa lista, e também, colocar essas TextBox em colunas especificas.

    As informações que eu vou coletar do usuario são de arquivos na maquina dele, eu mostro um Dialog, pego a pasta que o usuario escolheu, pego todos os arquivos dentro dessa pasta, e adiciono a uma List, de tipo FileInfo (List<FileInfo), e depois eu uso as informações nela para povoar a ListView. Então, como eu faria as coisas dessa maneira, com esse "novo layout", colocando TextBox em certas colunas da ListView, e fazendo isso programaticamente?

    A proposito, se alguém ficou com alguma duvida, segue o código que eu uso no WinForm:

    private void btn_SelectFolder_Click(object sender, EventArgs e)
    {
        if (FolderBrowserDialog.ShowDialog() == DialogResults.OK)
        {
            GetFilesFromFolder(FolderBrowserDialog.SelectedPath);
            AddFilesToList();
        }
    }
    
    private void GetFilesFromFolder(string path)
    {
        string[] fileNames = Directory.GetFiles(path);
    
        foreach(string file in fileNames)
        {
            // "filesList" é um List<FileInfo>
            filesList.Add(new FileInfo(file));
        }
    }
    
    private void AddFilesToList()
    {
        foreach(FileInfo file in filesList)
        {
            // NOME DO ARQUIVO, NA PRIMEIRA COLUNA DA LISTA
            myList.Items.Add(file.Name);
    
            // EXTENSÃO DO ARQUIVO, EM UMA COLUNA
            // COM NOME "EXTENSION"
            // É PRATICAMENTE NO MESMO ITEM (LINHA),
            //SÓ QUE COMO SUBITEM PARA IR PARA SEGUNDA COLUNA
            myList.Items[i].SubItems.Add(file.Extension);
            ...
        }
    }

    Como podem ver, é bem simples, o que eu queria saber é como fazer isso, com aquelas mudanças que falei, no WPF.

    quarta-feira, 25 de janeiro de 2017 14:26

Respostas

  • Olá,

    Bom, eu vou colocar uma explicação bem resumida e básica, mas é importante que você pesquise mais sobre o tema para entender bem o conceito.... Sugiro a leitura do livro WPF Unleashed (em inglês).

    No seu cenário, você teria uma propriedade de coleção no seu fonte C#. Esta colção geralmente é criada com o tipo ObservableCollection<seu tipo>. Onde "seu tipo" é a classe que você vai utilizar para abstrair o que está controlando. A ObservableCollection trabalha como um container, tipo uma List<>, com a diferença que ela "observa" as alterações nos objetos dela e informa os controles que estão apontados para ela se atualizar. No fonte C#, você pode alimentar esta coleção com os dados dos seus arquivos lidos.

    No XAML, você terá uma ListView com Binding na propriedade ItemSource para a sua coleção no código C#. Para que o .NET faça a ponte entre o XAML e o fonte C#, no construtor da classe de sua janela, você informa que o contexto de sua janela é ela mesmo, assim:

    this.DataContext = this;

    Isso vai informar a janela no XAML que pode encontrar qualquer propriedade publica no seu fonte C#... Vamos dizer que sua coleção está definida em sua classe assim:

    public ObservableCollection<Arquivo> ListaArquivos {get; set;}

    No seu XAML, você poderá apontar que o ListView use esta coleção como fonte de dados, assim:

    <ListView ItemsSource={Binding ListaArquivos, Mode=TwoWay}>
    ...
    </ListView>

    Como oseu objetivo é permitir editar alguma coluna da ListView, você pode incluir um TextBox nesta coluna para permitir edição. Estas colunas, devem apontar via binding para as propriedades da sua classe.

    Seguindo os exemplos acima, na classe Arquivo acima, digamos que exista a propriedade Nome do tipo string, na coluna do Nome você colocaria {Binding Nome}, assim o XAML sabe que você quer referenciar a proprieade Nome, e como o ListView está com binding na coleção de arquivos, o XAML sabe que para cada classe Arquivo, deve montar esta coluna com a informação da propriedade Nome.

    Quando você alterar a propriedade na ListView, como é uma ObservableCollection, já estará alterando diretamente na coleção no fonte C#... então você sempre terá as informações atualizadas no fonte C#.

    Abaixo um exemplo de uma ListView com Binding e com permissão de edição em uma coluna:

    <Grid>
        <ListView ItemsSource="{Binding Items}">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Name">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <TextBox Name="txtName" Text="{Binding Mode=OneTime}" IsReadOnly="True" MouseDoubleClick="txtName_MouseDoubleClick" Width="100"/>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>                    
                </GridView>                
            </ListView.View>
        </ListView>
    </Grid>

    E no fonte C#:

    public partial class MainWindow : Window
    {
        public List<string> Items { get; set; }
        public MainWindow()
        {
            InitializeComponent();
            Items = new List<string>();
            LoadItems();
            DataContext = this;
        }
    
        private void txtName_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            TextBox currentTextBox = (TextBox)sender;
            if (currentTextBox.IsReadOnly)
                currentTextBox.IsReadOnly = false;
            else
                currentTextBox.IsReadOnly = true;
        }
    
        private void LoadItems()
        {
            Items.Add("Coffee");
            Items.Add("Sugar");
            Items.Add("Cream");
        }
    }
    

    Espero ter ajudado em algo.


    Fabio Rosa.

    • Marcado como Resposta Cliffinho sexta-feira, 27 de janeiro de 2017 12:51
    sexta-feira, 27 de janeiro de 2017 10:23

Todas as Respostas

  • Olá,

    Acho que este artigo pode te ajudar. Apesar de estar em VB .NET, a lógica é a mesma, e o XAML pode ser o mesmo também.

    Utilizando Controle ListView - WPF

    Att,



    Fabio Rosa.

    quarta-feira, 25 de janeiro de 2017 15:41
  • De fato eu consegui compreender mais algumas coisas, mas enquanto a adicionar uma TextBox em uma coluna especifica, programaticamente?

    Quer dizer, como eu manipulo o XAML via código C#? (por mais que não faça tanto sentido, já que o objetivo é separar as coisas)

    quinta-feira, 26 de janeiro de 2017 12:12
  • Olá,

    Bom, eu vou colocar uma explicação bem resumida e básica, mas é importante que você pesquise mais sobre o tema para entender bem o conceito.... Sugiro a leitura do livro WPF Unleashed (em inglês).

    No seu cenário, você teria uma propriedade de coleção no seu fonte C#. Esta colção geralmente é criada com o tipo ObservableCollection<seu tipo>. Onde "seu tipo" é a classe que você vai utilizar para abstrair o que está controlando. A ObservableCollection trabalha como um container, tipo uma List<>, com a diferença que ela "observa" as alterações nos objetos dela e informa os controles que estão apontados para ela se atualizar. No fonte C#, você pode alimentar esta coleção com os dados dos seus arquivos lidos.

    No XAML, você terá uma ListView com Binding na propriedade ItemSource para a sua coleção no código C#. Para que o .NET faça a ponte entre o XAML e o fonte C#, no construtor da classe de sua janela, você informa que o contexto de sua janela é ela mesmo, assim:

    this.DataContext = this;

    Isso vai informar a janela no XAML que pode encontrar qualquer propriedade publica no seu fonte C#... Vamos dizer que sua coleção está definida em sua classe assim:

    public ObservableCollection<Arquivo> ListaArquivos {get; set;}

    No seu XAML, você poderá apontar que o ListView use esta coleção como fonte de dados, assim:

    <ListView ItemsSource={Binding ListaArquivos, Mode=TwoWay}>
    ...
    </ListView>

    Como oseu objetivo é permitir editar alguma coluna da ListView, você pode incluir um TextBox nesta coluna para permitir edição. Estas colunas, devem apontar via binding para as propriedades da sua classe.

    Seguindo os exemplos acima, na classe Arquivo acima, digamos que exista a propriedade Nome do tipo string, na coluna do Nome você colocaria {Binding Nome}, assim o XAML sabe que você quer referenciar a proprieade Nome, e como o ListView está com binding na coleção de arquivos, o XAML sabe que para cada classe Arquivo, deve montar esta coluna com a informação da propriedade Nome.

    Quando você alterar a propriedade na ListView, como é uma ObservableCollection, já estará alterando diretamente na coleção no fonte C#... então você sempre terá as informações atualizadas no fonte C#.

    Abaixo um exemplo de uma ListView com Binding e com permissão de edição em uma coluna:

    <Grid>
        <ListView ItemsSource="{Binding Items}">
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Name">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <TextBox Name="txtName" Text="{Binding Mode=OneTime}" IsReadOnly="True" MouseDoubleClick="txtName_MouseDoubleClick" Width="100"/>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>                    
                </GridView>                
            </ListView.View>
        </ListView>
    </Grid>

    E no fonte C#:

    public partial class MainWindow : Window
    {
        public List<string> Items { get; set; }
        public MainWindow()
        {
            InitializeComponent();
            Items = new List<string>();
            LoadItems();
            DataContext = this;
        }
    
        private void txtName_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            TextBox currentTextBox = (TextBox)sender;
            if (currentTextBox.IsReadOnly)
                currentTextBox.IsReadOnly = false;
            else
                currentTextBox.IsReadOnly = true;
        }
    
        private void LoadItems()
        {
            Items.Add("Coffee");
            Items.Add("Sugar");
            Items.Add("Cream");
        }
    }
    

    Espero ter ajudado em algo.


    Fabio Rosa.

    • Marcado como Resposta Cliffinho sexta-feira, 27 de janeiro de 2017 12:51
    sexta-feira, 27 de janeiro de 2017 10:23
  • Funcionou exatamente do jeito que eu precisava, valeu Fabio!
    sexta-feira, 27 de janeiro de 2017 12:51