2009-12-29 33 views
15

¿Cómo uso Datagrid.SelectedItem para seleccionar una fila mediante programación?WPF Datagrid establece la fila seleccionada

¿Tengo que crear primero un objeto IEnumerable de DataGridRow y pasar la fila correspondiente a esta propiedad SelectedItem o cómo lo hago?

EDIT:

que necesito para que coincida con el contenido celular de la célula primeras columnas con una primera TextBox.Text, antes de seleccionar la fila.

+0

¿Está utilizando WPF Toolkit DataGrid? – jsmith

+0

@jsmith Sí, ese es el que estoy usando. –

Respuesta

32

por favor, compruebe si el siguiente código funcionaría para usted; itera a través de las celdas de la primera columna de Datagris y comprueba si el contenido de la celda es igual al valor textbox.text y selecciona la fila.

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

esperanza que esta ayuda, que se refiere a

+0

+1 Me salvas con la fila.MoveFocus! jajaja, me estaba volviendo loco ... –

+0

Puede haber casos en los que encuentre agregar 'dataGrid.UpdateLayout()' justo antes de 'dataGrid.ScrollIntoView()' bastante útil, como se indica en [MSDN] (http: // msdn .microsoft.com/es-us/library/windows/apps/hh968031.aspx): * Cuando el contenido de la colección ItemsSource cambia, particularmente si se agregan o eliminan muchos elementos de la colección, es posible que deba llamar a UpdateLayout antes. para llamar a ScrollIntoView para que el elemento especificado se desplace hasta la ventana gráfica. * – jwaliszko

+0

Intenté esto y se colgó, pero el contexto es bueno. Lo que encontré fue que si el área de la cuadrícula visual es solo decir ...5 filas, pero tiene 20 filas de datos, el ContainerFromIndex (i) falla al devolver una fila y arroja un error si no está marcado como nulo. – DRapp

21

No es necesario para recorrer las filas DataGrid, se puede lograr su objetivo con una solución más sencilla. Para hacer coincidir su fila, puede iterar a través de su colección que estaba vinculada a su propiedad DataGrid.ItemsSource y luego asignarle este elemento a la propiedad DataGrid.SelectedItem mediante programación, alternativamente puede agregarlo a su colección DataGrid.SelectedItems si desea permitir que el usuario seleccione más de una fila. Ver el código de abajo: solución

<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

Me gusta la simplicidad de este ... –

+0

@boomhauer, me alegra oír eso :) –

+0

esto no funciona para mí ... Aunque lo quiero, realmente es malo. – jim

6

He buscado a un problema similar y tal vez mi manera le ayudará a nadie y que se enfrentan con ella.

Utilicé SelectedValuePath="id" en la definición de XAML DataGrid, y lo único programático que tengo que hacer es establecer DataGrid.SelectedValue en el valor deseado.

Sé que esta solución tiene sus pros y sus contras, pero en casos específicos es rápida y fácil.

Saludos

Marcin

+0

hola, sé que estoy respondiendo tarde ... Marcin es posible compartir el código que tiene este problema. esto me ayudará mucho. Estoy enfrentando un problema similar – user1221765

+0

¡Esta es la solución más simple! – Abbas

7

Es un poco más difícil de hacer lo que estamos tratando de hacer lo que yo prefiero, pero eso es debido a que en realidad no se unen directamente una a una DataGridDataTable.

Cuando enlaza DataGrid.ItemsSource a DataTable, realmente lo vincula al valor predeterminado DataView, no a la tabla en sí. Esta es la razón por la cual, por ejemplo, no tiene que hacer nada para crear filas DataGrid al hacer clic en el encabezado de una columna: esa funcionalidad está cocida en DataView y DataGrid sabe cómo acceder a ella (a través de la interfaz IBindingList).

El DataView implementa IEnumerable<DataRowView> (más o menos), y el DataGrid llena sus elementos iterando sobre esto. Esto significa que cuando haya vinculado DataGrid.ItemsSource a DataTable, su propiedad SelectedItem será DataRowView, no DataRow.

Si sabes todo esto, es bastante sencillo crear una clase contenedora que te permita exponer las propiedades a las que puedes vincular. Hay tres propiedades fundamentales:

  • Table, la DataTable,
  • , una de dos vías de propiedad enlazable de tipo DataRowView y
  • SearchText, una propiedad de cadena que, cuando está activada, se encuentra el primero haciendo coincidir DataRowView en la vista predeterminada de la tabla, establezca la propiedad y suba PropertyChanged.

Parece que este:

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

Y aquí es XAML que lo utiliza:

<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

Por todo lo que los demás parecen haber recibido más votos positivos, este parece ser el que discute cómo enlazar un conjunto de datos a un control XML de la manera que mejor pone a disposición las capacidades de la herramienta. –

3

// En general tenga acceso a todas las filas //

foreach (var item in dataGrid1.Items) 
{ 
    string str = ((DataRowView)dataGrid1.Items[1]).Row["ColumnName"].ToString(); 
} 

// Para acceder a las filas seleccionadas //

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

me encontré con este bastante reciente (en comparación con la edad de la cuestión) artículo de TechNet que incluye algunas de las mejores técnicas que pude encontrar sobre el tema:

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

Incluye detalles que deben cubre la mayoría de los requisitos. Es importante recordar que si especifica plantillas personalizadas para DataGridRow para algunas filas, estas no tendrán DataGridCells dentro y entonces los mecanismos de selección normales de la grilla no funcionarán.

Deberá ser más específico sobre qué fuente de datos ha proporcionado la cuadrícula para responder la primera parte de su pregunta, como han dicho los demás.

1

me han cambiado el código de serge_gubenko y funciona mejor

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

Si alguien stumblng aquí tiene problemas con la selección rejilla interna que suceden después de OnSelectionChanged - después de intentar sin éxito todos los emisores de selección para una docena de horas la única Lo que funcionó para mí fue volver a cargar y repoblar DataGrid junto con el elemento seleccionado. No es nada elegante, pero en este momento no estoy seguro de si existe una mejor solución en mi situación.

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

Esto no proporciona una respuesta a la pregunta. Una vez que tenga suficiente [reputación] (https://stackoverflow.com/help/whats-reputation) podrá [comentar cualquier publicación] (https://stackoverflow.com/help/privileges/comment); en su lugar, [brinde respuestas que no requieran aclaración del autor de la pregunta] (https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can- i-do-instead). - [De la crítica] (/ review/low-quality-posts/16809469) – MikeT