web-dev-qa-db-ja.com

WPF Datagridセットの選択された行

Datagrid.SelectedItemを使用してプログラムで行を選択するにはどうすればよいですか?

最初にIEnumerableオブジェクトのDataGridRowを作成し、このSelectedItemプロパティに一致する行を渡す必要がありますか?

編集:

行を選択する前に、最初の列のセルの内容をTextBox.Textと最初に一致させる必要があります。

17
Tony The Lion

以下のコードが機能するかどうかを確認してください。 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;
    }
}

よろしくお願いします

36
serge_gubenko

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

私は同様の問題の解決策を探しましたが、おそらく私のやり方があなたとそれに直面する人を助けるでしょう。

XAML DataGrid定義でSelectedValuePath="id"を使用しましたが、プログラムで行う必要があるのは、DataGrid.SelectedValueを目的の値に設定することだけです。

このソリューションには長所と短所がありますが、特定のケースでは高速で簡単です。

宜しくお願いします

マルシン

8
Marcin Sasin

あなたがやろうとしていることをやるのは私が好むよりも少し難しいですが、それはあなたがDataGridDataTableに直接バインドしていないからです。

_DataGrid.ItemsSource_をDataTableにバインドすると、実際にはテーブル自体ではなく、デフォルトのDataViewにバインドされます。これが、たとえば、列ヘッダーをクリックしたときにDataGridソート行を作成するために何もする必要がない理由です-その機能はDataViewに焼き付けられており、DataGridは(IBindingListインターフェイスを介して)アクセスする方法を知っています。

DataViewは_IEnumerable<DataRowView>_(多かれ少なかれ)を実装し、DataGridはこれを反復してその項目を埋めます。つまり、_DataGrid.ItemsSource_をDataTableにバインドした場合、そのSelectedItemプロパティはDataRowViewではなくDataRowになります。

これをすべて知っていれば、バインドできるプロパティを公開できるラッパークラスを構築するのは非常に簡単です。 3つの重要なプロパティがあります。

  • TableDataTable
  • Row、タイプDataRowViewの双方向バインド可能プロパティ、および
  • SearchTextは、設定されると、テーブルのデフォルトビューで最初に一致する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'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>
_
7
Robert Rossney

//一般にすべての行にアクセスするには//

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

私は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;
    }
}
1

ここでつまずいた人がOnSelectionChangedの後に発生する内部グリッド選択に問題がある場合-すべての選択セッターを数十時間試して失敗した後、私のために働いた唯一のことは、選択されたアイテムとともにDataGridをリロードして再設定することでした。まったくエレガントではありませんが、この時点で、私の状況にもっと良い解決策があるかどうかはわかりません。

datagrid.ItemsSource = null
datagrid.ItemsSource = items;
datagrid.SelectedItem = selectedItem;
0
Mindaugas-kun

このかなり最近の(質問の時代と比較して)TechNetの記事には、このトピックで見つけられる最高のテクニックがいくつか含まれています。

WPF:DataGridの行またはセルをプログラムで選択してフォーカスする

ほとんどの要件をカバーする詳細が含まれています。一部の行のDataGridRowにカスタムテンプレートを指定すると、これらの行にDataGridCellが含まれないため、グリッドの通常の選択メカニズムが機能しないことに注意してください。

他の人が述べたように、質問の最初の部分に答えるために、グリッドに与えたデータソースをより具体的にする必要があります。

0
Andre Luus