Esta página mostra as diferenças entre as duas revisões da página.
Ambos os lados da revisão anterior Revisão anterior Próxima revisão | Revisão anterior | ||
revistaprogramar_arquivo:28_edicao:wpf_datagrids_na_pratica [2011/04/07 21:38] Caça |
revistaprogramar_arquivo:28_edicao:wpf_datagrids_na_pratica [2018/05/14 21:37] (Atual) |
||
---|---|---|---|
Linha 1: | Linha 1: | ||
====== WPF - Datagrids na Prática ====== | ====== WPF - Datagrids na Prática ====== | ||
+ | |||
+ | ====== Datagrid em Windows Presentation Foundation ====== | ||
+ | |||
+ | Neste artigo pretendo apresentar a Datagrid em Windows | ||
+ | Presentation Foundation (WPF) na .Net Framework 4.0. | ||
+ | Vou começar por uma breve apresentação teórica e em | ||
+ | seguida irei apresentar vários exemplos. De salientar que | ||
+ | não terei em conta Design Patterns. | ||
+ | |||
+ | A DataGrid é um controlo que permite apresentar dados, | ||
+ | representando cada linha um item de uma lista de objectos | ||
+ | do mesmo tipo e as colunas representam as várias | ||
+ | características do objecto. Ou seja, se na instância da | ||
+ | datagrid apresento uma lista de empregados, cada linha | ||
+ | representa um empregado e cada coluna representa uma | ||
+ | propriedade do empregado. | ||
+ | |||
+ | A classe DataGrid está incluída no namespace | ||
+ | System.Windows.Controls e é um selector que permite | ||
+ | seleccionar mais do que um item ao mesmo tempo e tem | ||
+ | por base a classe ItemsControl, | ||
+ | implementa a interface IAddChild. A seguinte imagem | ||
+ | mostra-nos esta hierarquia de classes. | ||
+ | |||
+ | {{: | ||
+ | |||
+ | |||
+ | Vejamos agora algumas propriedades, | ||
+ | relevantes da DataGrid. | ||
+ | |||
+ | |||
+ | ===== As propriedades mais relevantes são: ===== | ||
+ | |||
+ | * Name: permite definir o nome. | ||
+ | * Foreground: permite definir a cor da letra. | ||
+ | * Background: permite definir a cor de fundo. | ||
+ | * AlternatingRowBackground; | ||
+ | * Item numa Lista Não OrdenadaWidth; | ||
+ | * ColumnWidth; | ||
+ | * RowHeight; MinRowHeight: | ||
+ | * GridLinesVisibility: | ||
+ | * SelectionMode; | ||
+ | * AutoGenerateColumns: | ||
+ | * Columns: permite obter a colecção de colunas. | ||
+ | * CellStyle: permite definir o estilo da célula. | ||
+ | * ColumnHeaderStyle: | ||
+ | * CanUserAddRows: | ||
+ | * CanUserDeleteRows: | ||
+ | * CanUserReorderColumns permite que o utilizador organize as colunas. | ||
+ | * CanUserResizeColumns: | ||
+ | * CanUserResizeRows: | ||
+ | * CanUserSortColumns: | ||
+ | * CurrentColumn: | ||
+ | * CurrentCell: | ||
+ | * CurrentItem: | ||
+ | * SelectedCells: | ||
+ | * SelectedIndex: | ||
+ | * SelectedItem: | ||
+ | * SelectedItems: | ||
+ | * HasItems: permite saber se a datagrid contém itens. | ||
+ | * Items: permite obter a lista de itens. | ||
+ | * ItemsSource: | ||
+ | * ItemTemplate; | ||
+ | |||
+ | <note normal> | ||
+ | propriedade ItemsSource e apenas se pode usar uma | ||
+ | delas. Quando se usa a propriedade ItemsSource, | ||
+ | possível adicionar ou remover itens através desta | ||
+ | propriedade ou através da propriedade Items. No entanto, | ||
+ | se atribuirmos uma ObservableCollection ao ItemsSource, | ||
+ | essa questão é ultrapassada.</ | ||
+ | |||
+ | ===== Os métodos mais relevantes são: ===== | ||
+ | |||
+ | * BeginEdit: permite invocar o comando BeginEditCommand, | ||
+ | * CommitEdit: permite invocar o comando CommitEditCommand para célula ou linha que está em modo de edição. | ||
+ | * CancelEdit: | ||
+ | |||
+ | ===== Os eventos mais relevantes são: ===== | ||
+ | |||
+ | * BeginningEdit: | ||
+ | * PreparingCellForEdit: | ||
+ | * CellEditEnding: | ||
+ | * RowEditEnding: | ||
+ | * SelectionChanged: | ||
+ | * CurrentCellChanged: | ||
+ | * SelectedCellsChanged: | ||
+ | |||
+ | |||
+ | <note normal> | ||
+ | pormenorizado sobre as propriedades, | ||
+ | da DataGrid, deve consultar a página DataGrid Class no | ||
+ | MSDN: [[http:// | ||
+ | |||
+ | |||
+ | Antes de passarmos aos exemplos práticos, vejamos os | ||
+ | vários tipos de colunas da DataGrid. | ||
+ | |||
+ | Em WPF, podemos definir os seguintes tipos de colunas: | ||
+ | * DataGridTextColumn – permite apresentar e editar texto; | ||
+ | * DataGridCheckBoxColumn – permite atribuir um valor lógico (verdadeiro / falso) | ||
+ | * DataGridComboBoxColumn – permite seleccionar uma opção de um conjunto de opções; | ||
+ | * DataGridHyperlinkColumn – permite adicionar uma hiperligação; | ||
+ | * DataGridTemplateColumn – permite definir o template da coluna, isto é, podemos customizar a coluna. | ||
+ | |||
+ | |||
+ | O seguinte diagrama, permite-nos perceber melhor qual a | ||
+ | classe de base de cada tipo de coluna. | ||
+ | |||
+ | {{: | ||
+ | |||
+ | |||
+ | ====== Exemplos práticos ====== | ||
+ | |||
+ | |||
+ | Passemos agora aos exemplos práticos. | ||
+ | |||
+ | |||
+ | <note normal> | ||
+ | obter em: [[http:// | ||
+ | |||
+ | |||
+ | Suponhamos que temos um objecto empregado (Employee) e um conjunto de empregados (Employees). O empregado, tem como principais características: | ||
+ | |||
+ | |||
+ | {{: | ||
+ | |||
+ | |||
+ | <note normal> | ||
+ | |||
+ | • A classe Employee implementa a interface | ||
+ | INotifyPropertyChanged para que sejam feitas notificações quando alguma propriedade é alterada. Isto é em parte responsável pela actualização da informação na Datagrid. | ||
+ | |||
+ | • A classe Employees é uma ObservableCollection de Employee, porque pretendo que sejam feitas notificações quando um ou mais empregrados são adicionados/ | ||
+ | |||
+ | |||
+ | ===== 1º Exemplo: ===== | ||
+ | |||
+ | Objectivo: Apresentar numa janela uma Datagrid com | ||
+ | uma lista de empregados, as colunas da Datagrid devem | ||
+ | ser geradas automaticamente: | ||
+ | |||
+ | |||
+ | * XAML | ||
+ | <code xml>< | ||
+ | Grid.Column=" | ||
+ | Grid.Row=" | ||
+ | AutoGenerateColumns=" | ||
+ | |||
+ | * Code Behind: | ||
+ | |||
+ | Usando a propriedade ItemsSource para atribuir a lista de | ||
+ | empregados. | ||
+ | |||
+ | <code csharp> | ||
+ | var employees=new Employees(); | ||
+ | // add the employee list | ||
+ | //using ItemsSource | ||
+ | dataGridEmployees.ItemsSource = employees;</ | ||
+ | |||
+ | |||
+ | Usando a propriedade Items para atribuir a lista de | ||
+ | empregados. | ||
+ | |||
+ | |||
+ | <code csharp> | ||
+ | var employees=new Employees(); | ||
+ | // add the employee list | ||
+ | //using Items | ||
+ | foreach (var employee in employees) | ||
+ | dataGridEmployees.Items.Add(employee); | ||
+ | }</ | ||
+ | |||
+ | * Resultado: | ||
+ | |||
+ | {{: | ||
+ | |||
+ | |||
+ | ===== 2º Exemplo: ===== | ||
+ | |||
+ | Objectivo: Apresentar numa janela uma Datagrid com uma lista de empregados, as colunas da Datagrid não devem ser geradas automaticamente e apenas se pretende visualizar as colunas relativas ao nome, se é patrão, salário e taxas. | ||
+ | |||
+ | |||
+ | * XAML: | ||
+ | |||
+ | <code xml>< | ||
+ | Grid.Column=" | ||
+ | Grid.Row=" | ||
+ | AutoGenerateColumns=" | ||
+ | < | ||
+ | < | ||
+ | Header=" | ||
+ | Binding=" | ||
+ | < | ||
+ | Header=" | ||
+ | Binding=" | ||
+ | < | ||
+ | Header=" | ||
+ | < | ||
+ | Header=" | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | <note normal> | ||
+ | • Através do objecto Binding da coluna é definido qual a | ||
+ | propriedade do objecto que se vai apresentar. | ||
+ | • Foram definidas as medidas para a largura, largura | ||
+ | mínima e largura máxima das várias colunas.</ | ||
+ | |||
+ | * Code Behind: | ||
+ | |||
+ | <code csharp> | ||
+ | var employees = new Employees(); | ||
+ | // add the employee list | ||
+ | dataGridEmployees.ItemsSource = employees; | ||
+ | }</ | ||
+ | |||
+ | * Resultado: | ||
+ | |||
+ | (A imagem com o resultado pode ser visto na coluna do | ||
+ | lado direito em cima de todo) | ||
+ | |||
+ | {{: | ||
+ | |||
+ | |||
+ | ===== 3º Exemplo: ===== | ||
+ | |||
+ | Objectivo: Formatar a apresentação do salário e das taxas, ou seja, um salário com valor 0 (zero) deve apresentar o valor “Não está atribuído” e os salários que estejam definidos devem apresentar o símbolo da moeda € (euro). As Taxas devem apresentar o valor da taxa com o símbolo de percentagem. | ||
+ | |||
+ | Neste exemplo, temos necessidade de criar duas classes, cada classe representa o conversor que será usado no objecto de Binding da coluna. O conversor será responsável por transformar o valor original no valor que é pretendido apresentar. Ambas as classes implementam a interface IValueConverter. | ||
+ | |||
+ | Portanto, o conversor para o salário será definido da seguinte forma: | ||
+ | |||
+ | <code csharp> | ||
+ | public class SalaryValueConverter: | ||
+ | private const string NotDefinedValue = "Não está definido"; | ||
+ | private const string EuroSymbol = " | ||
+ | public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { | ||
+ | if (value == null || (double.Parse(value.ToString()) == 0)) | ||
+ | return NotDefinedValue; | ||
+ | return string.Format(" | ||
+ | } | ||
+ | public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { | ||
+ | if (value is string && value.ToString().Equals(NotDefinedValue)) | ||
+ | return 0; | ||
+ | return value is string && value.ToString().Contains(EuroSymbol)? | ||
+ | double.Parse(value.ToString().Replace(EuroSymbol, | ||
+ | } | ||
+ | }</ | ||
+ | |||
+ | |||
+ | O conversor para a taxa será definido da seguinte forma: | ||
+ | |||
+ | <code csharp> | ||
+ | public class | ||
+ | RatesValueConverter: | ||
+ | private const string PercentageSymbol = " | ||
+ | public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture){ | ||
+ | if (value is int && int.Parse(value.ToString()) == 0) | ||
+ | return string.Empty; | ||
+ | return string.Format(" | ||
+ | } | ||
+ | public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture){ | ||
+ | throw new NotImplementedException(); | ||
+ | } | ||
+ | }</ | ||
+ | |||
+ | * XAML: | ||
+ | |||
+ | É necessário adicionar o namespace dos resources | ||
+ | |||
+ | <code xml> | ||
+ | |||
+ | Nos resources da janela, inicializamos os dois conversores | ||
+ | |||
+ | <code xml>< | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | É necessário alterar o Binding das colunas, é neste objecto que definimos o conversor aplicar. | ||
+ | |||
+ | <code xml>< | ||
+ | Grid.Column=" | ||
+ | Grid.Row=" | ||
+ | AutoGenerateColumns=" | ||
+ | < | ||
+ | < | ||
+ | Header=" | ||
+ | Binding=" | ||
+ | < | ||
+ | Header=" | ||
+ | Binding=" | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | * Code Behind: | ||
+ | |||
+ | <code csharp> | ||
+ | var employees = new Employees(); | ||
+ | // add the employee list | ||
+ | dataGridEmployees.ItemsSource = employees; | ||
+ | }</ | ||
+ | |||
+ | * Resultado: | ||
+ | |||
+ | {{: | ||
+ | |||
+ | |||
+ | ===== 4º Exemplo: ===== | ||
+ | |||
+ | Objectivo: Apresentar uma coluna extra, que será o resultado do produto do salário com a taxa associada. | ||
+ | |||
+ | É necessário criar um conversor, que receba o salário e a taxa, e devolva o resultado final, formado. Neste caso, como é preciso receber dois valores a classe terá que implementar a interface IMultiValueConverter. | ||
+ | |||
+ | <code csharp> | ||
+ | public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) { | ||
+ | double salary = 0.0; | ||
+ | int rates = 0; | ||
+ | if (values[0] is double) | ||
+ | salary = double.Parse(values[0].ToString()); | ||
+ | if (values[1] is int) | ||
+ | rates = int.Parse(values[1].ToString()); | ||
+ | if (salary == 0 && rates == 0) | ||
+ | return string.Empty; | ||
+ | return string.Format(" | ||
+ | } | ||
+ | public object[] ConvertBack(object value, Type[] targetTypes, | ||
+ | throw new NotImplementedException(); | ||
+ | } | ||
+ | }</ | ||
+ | |||
+ | <note normal> | ||
+ | método Convert, recebe os valores de acordo com a ordem | ||
+ | que for definido no multibinding que será definido na | ||
+ | coluna.</ | ||
+ | |||
+ | |||
+ | * XAML: | ||
+ | |||
+ | <code xml>< | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | </ | ||
+ | |||
+ | Adicionamos a nova coluna com o nome “Salário Final”, repare-se que usou-se um Multibinding, | ||
+ | |||
+ | <code xml>< | ||
+ | < | ||
+ | MinWidth=" | ||
+ | < | ||
+ | Width=" | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | <Binding Path=" | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | < | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | |||
+ | * Code Behind: | ||
+ | |||
+ | <code csharp> | ||
+ | var employees = new Employees(); | ||
+ | // add the employee list | ||
+ | dataGridEmployees.ItemsSource = employees; | ||
+ | }</ | ||
+ | |||
+ | * Resultado: | ||
+ | |||
+ | {{: | ||
+ | |||
+ | ===== 5ºExemplo: ===== | ||
+ | |||
+ | Objectivo: Apresentar a coluna de Aniversário, | ||
+ | |||
+ | * XAML: | ||
+ | |||
+ | <code xml>< | ||
+ | MinWidth=" | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | SelectedDate=" | ||
+ | SelectedDateFormat=" | ||
+ | </ | ||
+ | </ | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | Text=" | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | <note normal> | ||
+ | Apenas apresento o XAML da coluna criada. | ||
+ | Foram definidos dois templates: um para o caso em que se está em modo de edição, em que usou aplicar um DatePicker. | ||
+ | O outro template apenas apresenta a data.</ | ||
+ | |||
+ | * Resultado: | ||
+ | |||
+ | {{: | ||
+ | |||
+ | |||
+ | ===== 6º Exemplo: ===== | ||
+ | |||
+ | Objectivo: Apresentar os empregados ordenados por Nome. | ||
+ | |||
+ | * Code Behind: | ||
+ | |||
+ | <code csharp> | ||
+ | var employees = new Employees(); | ||
+ | dataGridEmployees.ItemsSource = employees; | ||
+ | ICollectionView view = CollectionViewSource.GetDefaultView(dataGridEmployees.ItemsSource); | ||
+ | view.SortDescriptions.Add(new SortDescription(" | ||
+ | }</ | ||
+ | |||
+ | * Resultado: | ||
+ | |||
+ | {{: | ||
+ | |||
+ | ===== 7º Exemplo: ===== | ||
+ | |||
+ | Objectivo: Filtrar os empregados com salário superior a 500.00€. | ||
+ | |||
+ | * Code Behind: | ||
+ | |||
+ | <code csharp> | ||
+ | var employees = new Employees(); | ||
+ | dataGridEmployees.ItemsSource =employees; | ||
+ | ICollectionView view = CollectionViewSource.GetDefaultView(dataGridEmployees.ItemsSource); | ||
+ | view.Filter = new Predicate< | ||
+ | } | ||
+ | private bool EmployeesWithSalaryGreaterThan500(object param) { | ||
+ | var employee = (Employee)param; | ||
+ | if (employee.Salary > 500) | ||
+ | return true; | ||
+ | return false; | ||
+ | }</ | ||
+ | |||
+ | |||
+ | * Resultado: | ||
+ | |||
+ | {{: | ||
+ | |||
+ | |||
+ | ===== 8º Exemplo: ===== | ||
+ | |||
+ | Objectivo: As linhas da datagrid devem apresentar uma cor alternada. | ||
+ | |||
+ | * XAML: | ||
+ | |||
+ | <code xml>< | ||
+ | Grid.Column=" | ||
+ | Grid.Row=" | ||
+ | AutoGenerateColumns=" | ||
+ | AlternatingRowBackground=" | ||
+ | AlternationCount=" | ||
+ | </ | ||
+ | |||
+ | <code csharp> | ||
+ | var employees = new Employees(); | ||
+ | dataGridEmployees.ItemsSource = employees; | ||
+ | }</ | ||
+ | |||
+ | * Resultado: | ||
+ | |||
+ | {{: | ||
+ | |||
+ | ===== 9º Exemplo: ===== | ||
+ | |||
+ | Objectivo: Alterar a altura do cabeçalho das colunas, alterar o tipo de fonte da letra e tamanho e cor. Alterar a cor das linhas horizontais e verticais da datagrid. | ||
+ | |||
+ | * XAML: | ||
+ | |||
+ | Nos resources da Window, definimos o estilo que iremos aplicar às células. | ||
+ | |||
+ | <code xml>< | ||
+ | <Style x: | ||
+ | TargetType=" | ||
+ | <Setter Property=" | ||
+ | Value=" | ||
+ | <Setter Property=" | ||
+ | Value=" | ||
+ | <Setter Property=" | ||
+ | Value=" | ||
+ | </ | ||
+ | </ | ||
+ | < | ||
+ | Grid.Column=" | ||
+ | Grid.Row=" | ||
+ | AutoGenerateColumns=" | ||
+ | ColumnHeaderStyle=" | ||
+ | ColumnHeaderHeight=" | ||
+ | GridLinesVisibility=" | ||
+ | HorizontalGridLinesBrush=" | ||
+ | VerticalGridLinesBrush=" | ||
+ | |||
+ | * Code Behind: | ||
+ | |||
+ | <code csharp> | ||
+ | var employees = new Employees(); | ||
+ | dataGridEmployees.ItemsSource = employees; | ||
+ | }</ | ||
+ | |||
+ | * Resultado: | ||
+ | |||
+ | {{: | ||
+ | |||
+ | ===== 10º Exemplo: ===== | ||
+ | |||
+ | Objectivo: Ao seleccionar uma célula e mostrar uma mensagem de aviso de que foi detectada uma alteração, | ||
+ | |||
+ | * XAML: | ||
+ | |||
+ | <code xml>< | ||
+ | Grid.Column=" | ||
+ | Grid.Row=" | ||
+ | AutoGenerateColumns=" | ||
+ | SelectionMode=" | ||
+ | SelectionUnit=" | ||
+ | CurrentCellChanged=" | ||
+ | |||
+ | * Code Behind: | ||
+ | |||
+ | <code csharp> | ||
+ | { | ||
+ | var employees = new Employees(); | ||
+ | dataGridEmployees.ItemsSource = employees; | ||
+ | } | ||
+ | private void DataGridEmployeesCurrentCellChanged(objectsender, | ||
+ | Employee selectedEmployee = (Employee)dataGridEmployees.CurrentItem; | ||
+ | string message = String.Format(" | ||
+ | MessageBox.Show(message); | ||
+ | }</ | ||
+ | |||
+ | * Resultado: | ||
+ | |||
+ | {{: | ||
+ | |||
+ | ====== Conclusão ====== | ||
+ | |||
+ | |||
+ | Demo do artigo: [[http:// | ||
+ | |||
+ | Contém: | ||
+ | * Diagrama de Classes da hierarquia das colunas | ||
+ | * Diagrama de classes da hierarquia da Datagrid | ||
+ | * Diagrama de classes do modelo usado no demo | ||
+ | * Interfaces | ||
+ | * Classes de dados | ||
+ | * Conversores | ||
+ | * Janela principal com menu para os vários exemplos | ||
+ | * Janelas dos vários exemplos | ||
+ | |||
+ | |||
+ | ===== Referências: | ||
+ | * MSDN: DataGrid Class - .Net Framework 4.0: [[http:// | ||
+ | * WindowsClient.Net: | ||
+ | |||
+ | |||
+ | Link para o artigo: [[http:// | ||
+ | |||
+ | ===== Autor ===== | ||
+ | |||
+ | {{: | ||
+ | |||
+ | É licenciada em Matemática – Especialidade em Computação, | ||
+ | O entusiasmo pela área resultou na obtenção dos títulos de Microsoft Certified Profissional Developer – Windows 3.5, Microsoft Certified Tecnology Specialist – WPF 3.5, WPF 4 e Windows Forms. Faz parte de várias comunidades, | ||
+ | |||
[[http:// | [[http:// | ||
+ | |||
+ | {{tag> |