WPF Datagrid ensemble de la ligne sélectionnée
comment utiliser le Datagrid.SelectedItem
pour sélectionner une ligne par programmation?
Est-ce que je dois d'abord créer un IEnumerable
DataGridRow
objets et de passer la ligne correspondante à ce SelectedItem
propriété ou comment faire?
EDIT:
j'ai besoin de faire correspondre le contenu de la cellule de la première colonne de la cellule avec un TextBox.Text
d'abord, avant de sélectionner la ligne.
8 réponses
s'il vous plaît vérifier si le code ci-dessous fonctionne pour vous; il itère à travers les cellules de la première colonne de datagris et vérifie si le contenu de la cellule est égal à la zone de texte.valeur de texte et sélectionne la ligne.
for (int i = 0; i < dataGrid.Items.Count; i++)
{
DataGridRow row = (DataGridRow)dataGrid.ItemContainerGenerator.ContainerFromIndex(i);
TextBlock cellContent = dataGrid.Columns[0].GetCellContent(row) as TextBlock;
if (cellContent != null && cellContent.Text.Equals(textBox1.Text))
{
object item = dataGrid.Items[i];
dataGrid.SelectedItem = item;
dataGrid.ScrollIntoView(item);
row.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
break;
}
}
j'espère que cette aide, ce qui concerne
Vous n'avez pas besoin de parcourir le DataGrid
les lignes, vous pouvez atteindre votre objectif avec une solution plus simple.
Afin de correspondre à votre ligne vous pouvez itérer à travers votre collection qui était liée à votre DataGrid.ItemsSource
propriété puis assignez cet élément à vous DataGrid.SelectedItem
propriété programmatique, alternativement vous pouvez l'ajouter à votre DataGrid.SelectedItems
collection si vous souhaitez autoriser l'utilisateur à sélectionner plus d'une ligne. Voir le code ci-dessous:
<Window x:Class="ProgGridSelection.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" Loaded="OnWindowLoaded">
<StackPanel>
<DataGrid Name="empDataGrid" ItemsSource="{Binding}" Height="200"/>
<TextBox Name="empNameTextBox"/>
<Button Content="Click" Click="OnSelectionButtonClick" />
</StackPanel>
public partial class MainWindow : Window
{
public class Employee
{
public string Code { get; set; }
public string Name { get; set; }
}
private ObservableCollection<Employee> _empCollection;
public MainWindow()
{
InitializeComponent();
}
private void OnWindowLoaded(object sender, RoutedEventArgs e)
{
// Generate test data
_empCollection =
new ObservableCollection<Employee>
{
new Employee {Code = "E001", Name = "Mohammed A. Fadil"},
new Employee {Code = "E013", Name = "Ahmed Yousif"},
new Employee {Code = "E431", Name = "Jasmin Kamal"},
};
/* Set the Window.DataContext, alternatively you can set your
* DataGrid DataContext property to the employees collection.
* on the other hand, you you have to bind your DataGrid
* DataContext property to the DataContext (see the XAML code)
*/
DataContext = _empCollection;
}
private void OnSelectionButtonClick(object sender, RoutedEventArgs e)
{
/* select the employee that his name matches the
* name on the TextBox
*/
var emp = (from i in _empCollection
where i.Name == empNameTextBox.Text.Trim()
select i).FirstOrDefault();
/* Now, to set the selected item on the DataGrid you just need
* assign the matched employee to your DataGrid SeletedItem
* property, alternatively you can add it to your DataGrid
* SelectedItems collection if you want to allow the user
* to select more than one row, e.g.:
* empDataGrid.SelectedItems.Add(emp);
*/
if (emp != null)
empDataGrid.SelectedItem = emp;
}
}
c'est un peu plus compliqué de faire ce que vous essayez de faire que ce que je préférerais, mais c'est parce que vous ne liez pas directement un DataGrid
DataTable
.
Lorsque vous liez DataGrid.ItemsSource
DataTable
, vous êtes vraiment le liant à la valeur par défaut DataView
, pas à la table elle-même. C'est pourquoi, par exemple, vous ne devez rien faire pour faire un DataGrid
trier les lignes lorsque vous cliquez sur l'en - tête d'une colonne-cette fonctionnalité est stockée dans DataView
et DataGrid
sait comment y accéder (par le biais de l' IBindingList
interface).
DataView
implémente IEnumerable<DataRowView>
(plus ou moins), et le DataGrid
remplit ses éléments en itérant sur ceci. Cela signifie que lorsque vous avez lié DataGrid.ItemsSource
DataTable
, son SelectedItem
propriété sera une DataRowView
, pas DataRow
.
Si vous savez tout cela, c'est assez simple de construire une classe wrapper qui permet d'exposer les propriétés que vous pouvez lier à. Il y a trois clés propriétés:
Table
, leDataTable
,Row
, une propriété bidirectionnelle de type bindableDataRowView
etSearchText
, une propriété string qui, lorsqu'elle est définie, trouvera la première correspondanceDataRowView
dans la vue par défaut de la table, définissez leRow
propriété, et de souleverPropertyChanged
.
Il ressemble à ceci:
public class DataTableWrapper : INotifyPropertyChanged
{
private DataRowView _Row;
private string _SearchText;
public DataTableWrapper()
{
// using a parameterless constructor lets you create it directly in XAML
DataTable t = new DataTable();
t.Columns.Add("id", typeof (int));
t.Columns.Add("text", typeof (string));
// let's acquire some sample data
t.Rows.Add(new object[] { 1, "Tower"});
t.Rows.Add(new object[] { 2, "Luxor" });
t.Rows.Add(new object[] { 3, "American" });
t.Rows.Add(new object[] { 4, "Festival" });
t.Rows.Add(new object[] { 5, "Worldwide" });
t.Rows.Add(new object[] { 6, "Continental" });
t.Rows.Add(new object[] { 7, "Imperial" });
Table = t;
}
// you should have this defined as a code snippet if you work with WPF
private void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler h = PropertyChanged;
if (h != null)
{
h(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
// SelectedItem gets bound to this two-way
public DataRowView Row
{
get { return _Row; }
set
{
if (_Row != value)
{
_Row = value;
OnPropertyChanged("Row");
}
}
}
// the search TextBox is bound two-way to this
public string SearchText
{
get { return _SearchText; }
set
{
if (_SearchText != value)
{
_SearchText = value;
Row = Table.DefaultView.OfType<DataRowView>()
.Where(x => x.Row.Field<string>("text").Contains(_SearchText))
.FirstOrDefault();
}
}
}
public DataTable Table { get; private set; }
}
et voici XAML qui l'utilise:
<Window x:Class="DataGridSelectionDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dg="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit"
xmlns:DataGridSelectionDemo="clr-namespace:DataGridSelectionDemo"
Title="DataGrid selection demo"
Height="350"
Width="525">
<Window.DataContext>
<DataGridSelectionDemo:DataTableWrapper />
</Window.DataContext>
<DockPanel>
<Grid DockPanel.Dock="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label>Text</Label>
<TextBox Grid.Column="1"
Text="{Binding SearchText, Mode=TwoWay}" />
</Grid>
<dg:DataGrid DockPanel.Dock="Top"
ItemsSource="{Binding Table}"
SelectedItem="{Binding Row, Mode=TwoWay}" />
</DockPanel>
</Window>
j'ai cherché la solution à un problème similaire et peut-être que ma façon vous aidera ainsi que tous ceux qui font face avec elle.
j'ai utilisé SelectedValuePath="id"
dans le code XAML définition de grille de données, et programaticaly seule chose que j'ai à faire est de définir DataGrid.SelectedValue
à la valeur souhaitée.
je sais que cette solution a des avantages et des inconvénients, mais dans le cas précis est rapide et facile.
cordialement
Marcin
// En Général pour Accéder à toutes les lignes //
foreach (var item in dataGrid1.Items)
{
string str = ((DataRowView)dataGrid1.Items[1]).Row["ColumnName"].ToString();
}
//Pour Accéder À Des Lignes Sélectionnées //
private void dataGrid1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
try
{
string str = ((DataRowView)dataGrid1.SelectedItem).Row["ColumnName"].ToString();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
j'ai changé le code de serge_gubenko et il fonctionne mieux
for (int i = 0; i < dataGrid.Items.Count; i++)
{
string txt = searchTxt.Text;
dataGrid.ScrollIntoView(dataGrid.Items[i]);
DataGridRow row = (DataGridRow)dataGrid.ItemContainerGenerator.ContainerFromIndex(i);
TextBlock cellContent = dataGrid.Columns[1].GetCellContent(row) as TextBlock;
if (cellContent != null && cellContent.Text.ToLower().Equals(txt.ToLower()))
{
object item = dataGrid.Items[i];
dataGrid.SelectedItem = item;
dataGrid.ScrollIntoView(item);
row.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
break;
}
}
je suis tombé sur cet article de TechNet assez récent (par rapport à l'âge de la question) qui inclut certaines des meilleures techniques que j'ai pu trouver sur le sujet:
WPF: par programmation en Sélectionnant et en Concentrant une Ligne ou une Cellule dans un DataGrid
il comprend des détails qui devraient couvrir la plupart des exigences. Il est important de se rappeler que si vous spécifiez des gabarits personnalisés pour le DataGridRow pour certaines lignes, ceux-ci n'auront pas de DataGridCells à l'intérieur et alors les mécanismes normaux de sélection de la grille ne fonctionnent pas.
vous aurez besoin d'être plus précis sur la source de données que vous avez donné la grille pour répondre à la première partie de votre question, comme les autres l'ont déclaré.
si quelqu'un trébuchant ici a des problèmes avec la sélection de grille interne qui se produit après Onselection changed - après avoir essayé sans succès tous les setters de sélection pendant une douzaine d'heures la seule chose qui a fonctionné pour moi était recharger et repopuler DataGrid avec l'article sélectionné. Pas élégant du tout, mais à ce point je ne suis pas sûr si une meilleure solution existe dans ma situation.
datagrid.ItemsSource = null
datagrid.ItemsSource = items;
datagrid.SelectedItem = selectedItem;