2009-12-29 21 views
15

Come faccio a utilizzare il Datagrid.SelectedItem per selezionare una riga di codice?WPF Datagrid set riga selezionata

Devo prima creare un oggetto IEnumerable di DataGridRow e passare la riga corrispondente a questa proprietà SelectedItem o come faccio?

EDIT:

dobbiamo associare il contenuto della cella della cella prime colonne con un TextBox.Text prima, prima di selezionare la riga.

+0

Si sta utilizzando il WPF Toolkit DataGrid? – jsmith

+0

@jsmith Sì, è quello che sto usando. –

risposta

32

prega di verificare se il codice di seguito dovrebbe funzionare per voi; esegue un'iterazione celle della prima colonna della datagris e controlla se contenuto della cella è uguale al valore TextBox.Text e seleziona la riga.

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

speranza che questo aiuti, riguarda

+0

+1 Mi salvi con la riga. MoveFocus! ahahah, mi stava facendo impazzire ... –

+0

Ci possono essere casi in cui trovi l'aggiunta di 'dataGrid.UpdateLayout()' appena prima 'dataGrid.ScrollIntoView()' abbastanza utile - come notato in [MSDN] (http: // msdn .microsoft.com/it/us/library/windows/apps/hh968031.aspx): * Quando i contenuti della collezione ItemsSource cambiano, in particolare se molti elementi vengono aggiunti o rimossi dalla raccolta, potrebbe essere necessario chiamare UpdateLayout prima per chiamare ScrollIntoView per l'elemento specificato per scorrere nel viewport. * – jwaliszko

+0

Ho provato questo e si è bloccato su di me, ma il contesto è buono. Quello che ho trovato è che se l'area della griglia visiva è solo dire ...5 righe, ma hai 20 righe di dati, ContainerFromIndex (i) non riesce a restituire una riga e genera un errore se non è stato verificato nulla. – DRapp

21

Non è necessario per scorrere le DataGrid righe, è possibile raggiungere il tuo obiettivo con una soluzione più semplice. Per abbinare la tua riga puoi scorrere la tua collezione che era legata alla tua proprietà DataGrid.ItemsSource quindi assegnare questo elemento alla tua proprietà DataGrid.SelectedItem a livello di programmazione, in alternativa puoi aggiungerla alla tua collezione DataGrid.SelectedItems se vuoi consentire all'utente di selezionare più di una riga. Vedere il codice qui sotto: soluzione

<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

Mi piace la semplicità di questo ... –

+0

@boomhauer, felice di sentirlo :) –

+0

questo non funziona per me ... lo voglio, però, davvero male. – jim

6

ho cercato di problema simile e forse il mio modo vi aiuterà e chiunque faccia con esso.

Ho utilizzato SelectedValuePath="id" nella definizione di DataGrid XAML e solo la cosa programmatica che devo fare è impostare DataGrid.SelectedValue sul valore desiderato.

So che questa soluzione ha vantaggi e svantaggi, ma nel caso specifico è semplice e veloce.

migliori saluti

Marcin

+0

ciao, so che sto rispondendo tardi .. Marcin è possibile condividere il codice con questo problema. questo mi aiuterà molto .. Sto affrontando un problema simile – user1221765

+0

Questa è la soluzione più semplice! – Abbas

7

E 'un po' più complicato di fare ciò che si sta cercando di fare che preferisco, ma è perché non si ha realmente associare direttamente un DataGrid ad un DataTable.

Quando si associa DataGrid.ItemsSource a DataTable, lo si sta effettivamente vincolando al valore predefinito DataView, non al tavolo stesso. Questo è il motivo per cui, ad esempio, non devi fare nulla per creare una riga di ordinamento DataGrid quando fai clic sull'intestazione di una colonna - quella funzionalità viene infornata in DataView e DataGrid sa come accedervi (tramite l'interfaccia IBindingList).

Gli strumenti DataViewIEnumerable<DataRowView> (più o meno), e lo DataGrid riempie i suoi elementi ripetendo su questo. Ciò significa che quando hai associato DataGrid.ItemsSource a DataTable, la sua proprietà SelectedItem sarà DataRowView, non DataRow.

Se si conosce tutto questo, è abbastanza semplice creare una classe wrapper che consente di esporre le proprietà alle quali è possibile eseguire il binding. Ci sono tre proprietà fondamentali:

  • Table, il DataTable,
  • , a due vie proprietà associabile di tipo DataRowView, e
  • SearchText, una proprietà stringa che, quando è impostato, troveranno il prima corrispondenza DataRowView nella vista predefinita della tabella, impostare la proprietà e aumentare PropertyChanged.

Ecco come si presenta:

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

Ed ecco XAML che lo utilizza:

<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

Per tutti gli altri sembrano aver ottenuto più upvotes, questo sembra essere quello che discute su come associare un set di dati a un controllo XML nel modo migliore per rendere disponibili le funzionalità dello strumento. –

3

// In generale per accedere a tutte le righe //

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

// Per accedere alle righe selezionate //

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

mi sono imbattuto in questo piuttosto recente (rispetto all'età della questione) articolo di TechNet che include alcune delle migliori tecniche che ho trovato sul tema:

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

Esso include dettagli che dovrebbero coprire la maggior parte dei requisiti. È importante ricordare che se si specificano modelli personalizzati per DataGridRow per alcune righe, questi non avranno DataGridCells all'interno e quindi i normali meccanismi di selezione della griglia non funzionano.

Dovrai essere più specifico su quale origine dati hai fornito alla griglia per rispondere alla prima parte della tua domanda, come hanno affermato gli altri.

1

ho cambiato il codice di serge_gubenko e funziona meglio

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

Se qualcuno stumblng qui ha dei problemi con la selezione di rete interno che accadono dopo OnSelectionChanged - dopo aver senza successo provare tutte le setter di selezione per una dozzina di ore, il solo la cosa che ha funzionato per me è stata la ricarica e il ripopolamento di DataGrid insieme all'elemento selezionato. Per niente elegante, ma a questo punto non sono sicuro che esista una soluzione migliore nella mia situazione.

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

Questo non fornisce una risposta alla domanda. Una volta che hai [reputazione] sufficiente (https://stackoverflow.com/help/whats-reputation) sarai in grado di [commentare qualsiasi post] (https://stackoverflow.com/help/privileges/comment); invece [fornisci risposte che non richiedono chiarimenti da parte del richiedente] (https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can- i-do-, invece). - [Dalla recensione] (/ recensione/post di bassa qualità/16809469) – MikeT

Problemi correlati