WPF Datagrid 设置选定行
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1976087/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WPF Datagrid set selected row
提问by Tony The Lion
How do I use the Datagrid.SelectedItem
to select a row programmatically?
如何使用Datagrid.SelectedItem
以编程方式选择一行?
Do I first have to create a IEnumerable
of DataGridRow
objects and pass the matching row to this SelectedItem
property or how do I do it?
我首先要创建一个IEnumerable
的DataGridRow
对象和匹配的行传递给此SelectedItem
属性或我该怎么办呢?
EDIT:
编辑:
I need to match the cell content of the first columns cell with a TextBox.Text
first, before selecting the row.
TextBox.Text
在选择行之前,我需要将第一列单元格的单元格内容与第一个匹配。
回答by serge_gubenko
please check if code below would work for you; it iterates through cells of the datagris's first column and checks if cell content equals to the textbox.text value and selects the row.
请检查下面的代码是否适合您;它遍历 datagris 第一列的单元格并检查单元格内容是否等于 textbox.text 值并选择该行。
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;
}
}
hope this helps, regards
希望这有帮助,问候
回答by Mohammed A. Fadil
You don't need to iterate through the DataGrid
rows, you can achieve your goal with a more simple solution.
In order to match your row you can iterate through you collection that was bound to your DataGrid.ItemsSource
property then assign this item to you DataGrid.SelectedItem
property programmatically, alternatively you can add it to your DataGrid.SelectedItems
collection if you want to allow the user to select more than one row. See the code below:
您不需要遍历DataGrid
行,您可以使用更简单的解决方案来实现您的目标。为了匹配您的行,您可以遍历绑定到您的DataGrid.ItemsSource
属性的集合,然后以DataGrid.SelectedItem
编程方式将此项目分配给您的属性,或者,DataGrid.SelectedItems
如果您希望允许用户选择多个行,则可以将其添加到您的集合中。请参阅下面的代码:
<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;
}
}
回答by Marcin Sasin
I've searched solution to similar problem and maybe my way will help You and anybody who face with it.
我已经搜索过类似问题的解决方案,也许我的方法会帮助你和任何面临它的人。
I used SelectedValuePath="id"
in XAML DataGrid definition, and programaticaly only thing I have to do is set DataGrid.SelectedValue
to desired value.
我SelectedValuePath="id"
在 XAML DataGrid 定义中使用 过,并且在编程上我唯一要做的就是将其设置DataGrid.SelectedValue
为所需的值。
I know this solution has pros and cons, but in specific case is fast and easy.
我知道这个解决方案有利有弊,但在特定情况下既快速又简单。
Best regards
此致
Marcin
马尔钦
回答by Robert Rossney
It's a little trickier to do what you're trying to do than I'd prefer, but that's because you don't really directly bind a DataGrid
to a DataTable
.
做你想做的事情比我喜欢的要复杂一些,但那是因为你并没有真正直接将 a 绑定DataGrid
到 a DataTable
。
When you bind DataGrid.ItemsSource
to a DataTable
, you're really binding it to the default DataView
, not to the table itself. This is why, for instance, you don't have to do anything to make a DataGrid
sort rows when you click on a column header - that functionality's baked into DataView
, and DataGrid
knows how to access it (through the IBindingList
interface).
当您绑定DataGrid.ItemsSource
到 a 时DataTable
,您实际上是将它绑定到默认值DataView
,而不是表本身。这就是为什么,例如,DataGrid
当您单击列标题时,您无需执行任何操作即可对行进行排序 - 该功能已融入DataView
,并且DataGrid
知道如何访问它(通过IBindingList
界面)。
The DataView
implements IEnumerable<DataRowView>
(more or less), and the DataGrid
fills its items by iterating over this. This means that when you've bound DataGrid.ItemsSource
to a DataTable
, its SelectedItem
property will be a DataRowView
, not a DataRow
.
该DataView
工具IEnumerable<DataRowView>
(更多或更少),并DataGrid
在此通过重复填充其项目。这意味着当您绑定DataGrid.ItemsSource
到 a 时DataTable
,它的SelectedItem
属性将是 a DataRowView
,而不是 a DataRow
。
If you know all this, it's pretty straightforward to build a wrapper class that lets you expose properties that you can bind to. There are three key properties:
如果您了解所有这些,那么构建一个包装类就非常简单了,它允许您公开可以绑定到的属性。有三个关键属性:
Table
, theDataTable
,Row
, a two-way bindable property of typeDataRowView
, andSearchText
, a string property that, when it's set, will find the first matchingDataRowView
in the table's default view, set theRow
property, and raisePropertyChanged
.
Table
,DataTable
,Row
,类型为 的双向可绑定属性DataRowView
,以及SearchText
,一个字符串属性,当它被设置时,将DataRowView
在表的默认视图中找到第一个匹配项,设置该Row
属性并引发PropertyChanged
。
It looks like this:
它看起来像这样:
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; }
}
And here's XAML that uses it:
这是使用它的 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>
回答by Shan
// In General to Access all rows //
// 一般访问所有行 //
foreach (var item in dataGrid1.Items)
{
string str = ((DataRowView)dataGrid1.Items[1]).Row["ColumnName"].ToString();
}
//To Access Selected Rows //
//访问选定的行//
private void dataGrid1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
try
{
string str = ((DataRowView)dataGrid1.SelectedItem).Row["ColumnName"].ToString();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
回答by Marian Brestovansky
I have changed the code of serge_gubenko and it works better
我已经更改了 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;
}
}
回答by Mindaugas-kun
If anyone stumblng here has problems with internal grid selection happening after OnSelectionChanged - after unsuccessfully trying out all the selection setters for a dozen hours the only thing that worked for me was reloading and repopulating DataGrid along with selected item. Not elegant at all, but at this point I'm not sure if a better solution exists in my situation.
如果这里有人在 OnSelectionChanged 之后遇到内部网格选择问题 - 在尝试所有选择设置器十几个小时失败后,唯一对我有用的是重新加载和重新填充 DataGrid 以及所选项目。一点也不优雅,但此时我不确定在我的情况下是否存在更好的解决方案。
datagrid.ItemsSource = null
datagrid.ItemsSource = items;
datagrid.SelectedItem = selectedItem;
回答by Andre Luus
I came across this fairly recent (compared to the age of the question) TechNet article that includes some of the best techniques I could find on the topic:
我最近看到了这篇(与问题的年龄相比)TechNet 文章,其中包含我能找到的有关该主题的一些最佳技术:
WPF: Programmatically Selecting and Focusing a Row or Cell in a DataGrid
WPF:以编程方式选择并聚焦 DataGrid 中的行或单元格
It includes details that should cover most requirements. It is important to remember that if you specify custom templates for the DataGridRow for some rows that these won't have DataGridCells inside and then the normal selection mechanisms of the grid doesn't work.
它包括应涵盖大多数要求的详细信息。重要的是要记住,如果您为某些行的 DataGridRow 指定自定义模板,这些行中将没有 DataGridCells,那么网格的正常选择机制将不起作用。
You'll need to be more specific on what datasource you've given the grid to answer the first part of your question, as the others have stated.
正如其他人所说,您需要更具体地说明您为网格提供了哪些数据源来回答问题的第一部分。