WPF Datagrid установил выбранную строку

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

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

EDIT:

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

Ответ 1

пожалуйста, проверьте, работает ли код ниже для вас; он выполняет итерацию через ячейки первого столбца 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;
    }
}

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

Ответ 2

Вам не нужно перебирать строки 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

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

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

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

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

  • Table, DataTable,
  • Row, двухстороннее связующее свойство типа DataRowView и
  • SearchText, свойство string, которое при его установке найдет первое совпадение 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 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>

Ответ 4

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

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

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

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

Марцин

Ответ 5

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

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

Ответ 6

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

Ответ 7

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

WPF: программный выбор и фокусировка строки или ячейки в DataGrid

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

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

Ответ 8

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

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