WPF Datagrid设置选中的行
如何使用Datagrid.SelectedItem
以编程方式select行?
我首先必须创build一个IEnumerable
的DataGridRow
对象,并将匹配的行传递给这个SelectedItem
属性,或者我该怎么做?
编辑:
在select行之前,我需要首先将第一列单元格的单元格内容与TextBox.Text
匹配。
请检查下面的代码是否适合你; 它遍历datagris第一列的单元格,并检查单元格内容是否等于textbox.text值并select该行。
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; } }
希望这有助于问候
您不需要遍历DataGrid
行,您可以通过更简单的解决scheme实现您的目标。 为了匹配你的行,你可以遍历你绑定到你的DataGrid.ItemsSource
属性的集合,然后通过编程方式将这个项目分配给你DataGrid.SelectedItem
属性,或者你可以将它添加到你的DataGrid.SelectedItems
集合,如果你想允许用户select多个行。 请参阅下面的代码:
<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, eg: * empDataGrid.SelectedItems.Add(emp); */ if (emp != null) empDataGrid.SelectedItem = emp; } }
这样做比我更喜欢做一些小技巧,但是这是因为你不直接将DataGrid
绑定到DataTable
。
将DataGrid.ItemsSource
绑定到DataTable
,实际上是将其绑定到默认的DataView
,而不是绑定到表本身。 这就是为什么,例如,当你点击一个列标题时,你不必做任何事情就可以做一个DataGrid
sorting行 – 这个function被烘焙到DataView
, DataGrid
知道如何访问它(通过IBindingList
接口)。
DataView
实现IEnumerable<DataRowView>
(或多或less),并且DataGrid
通过遍历它来填充它的项目。 这意味着当您将DataGrid.ItemsSource
绑定到DataTable
,其SelectedItem
属性将是DataRowView
,而不是DataRow
。
如果你知道所有这一切,那么构build一个包装类就非常简单了,它允许你公开可绑定的属性。 有三个关键属性:
-
Table
,DataTable
, -
Row
,types为DataRowView
的双向可绑定属性,以及 -
SearchText
,一个string属性,当它被设置时,将在表的默认视图中find第一个匹配的DataRowView
,设置Row
属性,然后抛出PropertyChanged
。
它看起来像这样:
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; } }
这里是使用它的XAML:
<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>
我已经search解决类似的问题,也许我的方式将帮助你和任何人面对它。
我在XAML DataGrid定义中使用了SelectedValuePath="id"
,而我唯一需要做的事情是将DataGrid.SelectedValue
设置为期望的值。
我知道这个解决scheme有利有弊,但在特定情况下是快速和容易的。
最好的祝福
马尔钦
//通常访问所有行//
foreach (var item in dataGrid1.Items) { string str = ((DataRowView)dataGrid1.Items[1]).Row["ColumnName"].ToString(); }
//访问选定的行//
private void dataGrid1_SelectionChanged(object sender, SelectionChangedEventArgs e) { try { string str = ((DataRowView)dataGrid1.SelectedItem).Row["ColumnName"].ToString(); } catch (Exception ex) { MessageBox.Show(ex.Message); } }
我已经改变了serge_gubenko的代码,它效果更好
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; } }
我刚刚遇到了这个相当近的(与问题的年代相比)的TechNet文章,其中包括我可以find的有关该主题的一些最佳技术:
WPF:以编程方式select并聚焦DataGrid中的行或单元格
它包括应涵盖大多数要求的细节。 重要的是要记住,如果您为DataGridRow指定了一些自定义模板,这些模板中没有DataGridCells,那么网格的正常select机制将不起作用。
正如其他人所说的,您需要更具体地说明您提供网格的数据源来回答问题的第一部分。
如果有人在这里遇到OnSelectionChanged后发生内部网格select的问题 – 在十几个小时内没有成功尝试所有select设置器之后,唯一对我有用的是重新加载和重新填充DataGrid以及所选项目。 根本不算优雅,但在这一点上我不确定在我的情况下是否有更好的解决scheme。
datagrid.ItemsSource = null datagrid.ItemsSource = items; datagrid.SelectedItem = selectedItem;