2009-12-29 5 views
15

Как использовать Datagrid.SelectedItem для выбора строки программно?WPF Datagrid set selected row

Должен ли я сначала создать IEnumerable объектов DataGridRow и передать соответствующую строку этому SelectedItem или как это сделать?

РЕДАКТИРОВАТЬ:

мне нужно соответствовать содержанию ячейки, в первых столбцах с TextBox.Text первым, прежде чем выбрать строку.

+0

Вы используете WPF Toolkit DataGrid? – jsmith

+0

@jsmith Да, это тот, который я использую. –

ответ

32

, пожалуйста, проверьте, работает ли код ниже для вас; он выполняет итерацию через ячейки первого столбца datagris и проверяет, соответствует ли содержимое ячеек текстовому значению и выбирает строку.

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; 
    } 
} 

надеюсь, что это помогает, считает

+0

+1 Ты спасешь меня со строкой. hahaha, это сводило меня с ума ... –

+0

Бывают случаи, когда вы добавляете 'dataGrid.UpdateLayout()' непосредственно перед 'dataGrid.ScrollIntoView()' весьма полезно - как отмечено в [MSDN] (http: // msdn .microsoft.com/en-us/library/windows/apps/hh968031.aspx): * Когда содержимое коллекции ItemsSource изменяется, особенно если в коллекцию добавлено или удалено много элементов, вам может потребоваться позвонить UpdateLayout ранее для вызова ScrollIntoView для указанного элемента для прокрутки в окне просмотра. * – jwaliszko

+0

Я пробовал это, и он рухнул на меня, но контекст хороший. Я обнаружил, что если визуальная область сетки только говорит ...5 строк, но у вас есть 20 строк данных, ContainerFromIndex (i) не возвращает строку и выдает ошибку, если не проверен на значение null. – DRapp

21

Вам не нужно перебирать 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; 
    } 
} 
+3

Мне нравится простота этого ... –

+0

@boomhauer, рад слышать, что :) –

+0

это не работает для меня ... Я хочу, чтобы это было, хотя и очень плохо. – jim

6

Я искал решение подобной проблемы и, возможно, мой путь поможет вам и все, кто сталкиваются с ней.

Я использовал SelectedValuePath="id" в определении XAML DataGrid и программным образом, только мне нужно установить DataGrid.SelectedValue в нужное значение.

Я знаю, что это решение имеет свои плюсы и минусы, но в конкретном случае это быстро и просто.

С наилучшими пожеланиями

Marcin

+0

привет, я знаю, что я отвечаю поздно. Marcin можно поделиться кодом, имеющим эту проблему. это мне очень поможет .. Я столкнулся с аналогичным вопросом – user1221765

+0

Это самое простое решение! – Abbas

7

Это немного сложнее делать то, что вы пытаетесь сделать, чем я предпочел бы, но это потому, что вы на самом деле не напрямую связать DataGrid с DataTable.

Когда вы связываете DataGrid.ItemsSource с номером DataTable, вы действительно привязываете его к умолчанию DataView, а не к самой таблице. Вот почему, например, вам не нужно ничего делать, чтобы сделать строки сортировки DataGrid, когда вы нажимаете на заголовок столбца - эта функция испечена в DataView, а DataGrid знает, как получить к ней доступ (через интерфейс IBindingList).

DataView инвентарь IEnumerable<DataRowView> (более или менее), а DataGrid заполняет свои изделия, итерируя по этому вопросу. Это означает, что когда вы связали DataGrid.ItemsSource с DataTable, его SelectedItem будет DataRowView, а не DataRow.

Если вы знаете все это, довольно просто создать класс-оболочку, который позволяет вам открывать свойства, к которым вы можете привязать. Есть три основных свойства:

  • Table, то DataTable,
  • , двухсторонняя Привязываемое свойство типа DataRowView и
  • SearchText, струнный свойство, которое, когда оно установлено, найдет сначала сопоставьте DataRowView в представлении таблицы по умолчанию, установите свойство и поднимите 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> 
+2

При всем том, что другие, похоже, получили больше оборотов, похоже, это тот, который обсуждает, как привязать набор данных к элементу управления XML таким образом, чтобы он наилучшим образом предоставлял возможности этого инструмента. –

3

// В целом для доступа всех строк //

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); 
    } 
} 
0

Я наткнулся на это сравнительно недавно (по сравнению с возрастом вопрос) TechNet статьи, что включает в себя некоторые из самых лучших методов я смог найти по этой теме:

WPF: Programmatically Selecting and Focusing a Row or Cell in a DataGrid

Она включает в себя детали, которые должны охватывают большинство требований. Важно помнить, что если вы укажете настраиваемые шаблоны для DataGridRow для некоторых строк, они не будут иметь DataGridCells внутри, а затем обычные механизмы выбора сетки не будут работать.

Вам нужно будет уточнить, какой источник данных вы дали сетке, чтобы ответить на первую часть вашего вопроса, как заявили другие.

1

Я изменил код 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; 
    } 
} 
0

Если кто stumblng здесь есть проблемы с внутренним отбором сетки случающихся после OnSelectionChanged - после неудачной попытки всех сеттеров отбора на десяток часов только Вещь, которая работала для меня, - это перезагрузка и повторное заполнение DataGrid вместе с выбранным элементом. Не совсем элегантный, но на данный момент я не уверен, что в моей ситуации есть лучшее решение.

datagrid.ItemsSource = null 
datagrid.ItemsSource = items; 
datagrid.SelectedItem = selectedItem; 
+0

Это не дает ответа на вопрос. Когда у вас будет достаточно [репутации] (https://stackoverflow.com/help/whats-reputation), вы сможете [прокомментировать любое сообщение] (https://stackoverflow.com/help/privileges/comment); вместо этого [предоставить ответы, которые не требуют разъяснений у аськи) (https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can- я-делать-вместо этого). - [Из обзора] (/ review/low-quality-posts/16809469) – MikeT