Comment utiliser le Datagrid.SelectedItem
pour sélectionner une ligne par programme?
Dois-je d'abord créer un objet IEnumerable
of DataGridRow
et transmettre la ligne correspondante à cette propriété SelectedItem
ou comment procéder?
MODIFIER:
Je dois faire correspondre le contenu de la cellule de la première colonne avec un TextBox.Text
avant de sélectionner la ligne.
veuillez vérifier si le code ci-dessous fonctionne pour vous. il parcourt les cellules de la première colonne de datagris et vérifie si le contenu de la cellule est égal à la valeur textbox.text 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;
}
}
espérons que cela aide, salutations
Vous n'avez pas besoin de parcourir les lignes DataGrid
, vous pouvez atteindre votre objectif avec une solution plus simple . Afin de correspondre à votre ligne, vous pouvez parcourir la collection liée à votre propriété DataGrid.ItemsSource
puis vous attribue cet élément à votre propriété DataGrid.SelectedItem
par programme, ou vous pouvez également l'ajouter à votre collection DataGrid.SelectedItems
si vous souhaitez autoriser l'utilisateur à sélectionner plusieurs lignes. 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 délicat 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 une DataGrid
à une DataTable
.
Lorsque vous liez DataGrid.ItemsSource
à une DataTable
, vous le liez vraiment à la valeur par défaut DataView
, pas à la table elle-même. C'est pourquoi, par exemple, vous n'avez rien à faire pour créer un rang DataGrid
lorsque vous cliquez sur un en-tête de colonne. Cette fonctionnalité est intégrée à DataView
et DataGrid
sait comment y accéder (via l'interface IBindingList
).
DataView
implémente IEnumerable<DataRowView>
(plus ou moins), et DataGrid
remplit ses éléments en itérant dessus. Cela signifie que lorsque vous avez lié DataGrid.ItemsSource
à une DataTable
, sa propriété SelectedItem
sera une DataRowView
et non une DataRow
.
Si vous savez tout cela, il est assez simple de construire une classe wrapper qui vous permette d'exposer des propriétés auxquelles vous pouvez vous lier. Il y a trois propriétés principales:
Table
, le DataTable
,Row
, propriété bidirectionnelle pouvant être liée de type DataRowView
, et SearchText
, une propriété de chaîne qui, lorsqu'elle est définie, trouve la première DataRowView
correspondante dans la vue par défaut de la table, définit la propriété Row
et lève PropertyChanged
.Cela 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é une solution à un problème similaire et peut-être que ma façon de faire vous aidera, vous et tous ceux qui y font face.
J'ai utilisé SelectedValuePath="id"
dans la définition XAML DataGrid, et la seule chose que je dois faire par programme est de définir DataGrid.SelectedValue
sur la valeur souhaitée.
Je sais que cette solution a des avantages et des inconvénients, mais dans des cas spécifiques, elle est simple et rapide.
Meilleures salutations
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 aux 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 ça marche 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;
}
}
Si quelqu'un tombe par hasard ici a des problèmes avec la sélection de la grille interne après OnSelectionChanged - après avoir essayé sans succès tous les paramètres de sélection pendant une douzaine d'heures, la seule chose qui a fonctionné pour moi était de recharger et de repeupler DataGrid avec l'élément sélectionné. Pas élégant du tout, mais pour le moment, je ne suis pas sûr s'il existe une meilleure solution dans ma situation.
datagrid.ItemsSource = null
datagrid.ItemsSource = items;
datagrid.SelectedItem = selectedItem;
Je suis tombé sur cet article TechNet assez récent (comparé à l'âge de la question), qui inclut certaines des meilleures techniques que j'ai pu trouver sur le sujet:
WPF: Sélection et mise au point par programme d'une ligne ou d'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 modèles personnalisés pour DataGridRow pour certaines lignes, celles-ci ne contiendront pas DataGridCells et les mécanismes de sélection normaux de la grille ne fonctionneront pas.
Vous aurez besoin d’être plus précis sur la source de données que vous avez fournie à la grille pour répondre à la première partie de votre question, comme l’ont dit les autres.