从DataGrid WPF C#中选择的行获取特定单元格的数据

3

我有一个DataGrid,其中填充了来自我的SQL数据库的数据。 现在,我想要获取选中复选框所在行的特定单元格(第二个单元格)。

这是我目前拥有的: WPF XAML:

<DataGrid Name="myGrid">
    <DataGrid.Columns>
        <DataGridTemplateColumn>
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <CheckBox Checked="CheckBox_Checked"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    <DataGridTextColumn Header="CustomerID" Width="Auto" Binding="{Binding CustomerID}"/>
    <DataGridTextColumn Header="ItemID" Width="Auto" Binding="{Binding ItemID}"/>
<DataGrid>

C# 代码:

private void CheckBox_Checked(object sender, RoutedEventArgs e)
    {
        DataGrid row = (DataGrid)myGrid.SelectedItems[1];
        System.Windows.MessageBox.Show(row);
    }

运行时出现错误:

System.ArgumentOutOfRangeException

{"索引超出范围。必须是非负数且小于集合大小。\r\n参数名: index"}

我做错了什么?我需要使用其他方法来获取所需的单元格吗?


你需要哪个单元格数据?根据发布的 XAML,它只包含一个带有复选框的单元格。 - Rohit Vats
你的DataGrid里面没有任何数据?它是如何填充的? - Gábor Birkás
我省略了一些代码,认为它不是必要的。@GáborBirkás - thbl
@thbl 你是否在使用MVVM模式?为什么不将你的DataGrid上下文绑定到包含数据库行的ObservableCollection中呢?如果你需要我可以提供相关代码。 - Gábor Birkás
好的,请@GáborBirkás。希望我能让它工作。 - thbl
6个回答

9
我终于找到了!非常简单。
DataRowView drv = (DataRowView)myGrid.SelectedItem; 
String result = (drv["CustomerID"]).ToString(); 
MessageBox.Show(result);

1
无法工作。它显示了一个类型转换错误。 “无法将对象从类型'< >f__AnonymousType0`13” - Hardik Mandankaa

7
MVVM模式。
你的XAML代码:
<DataGrid Name="myGrid" Grid.Row="1"  SelectionMode="Single" AutoGenerateColumns="False" CanUserAddRows="True" ItemsSource="{Binding YourCollection}" IsReadOnly="True" Background="#FFB8C1CB">
<DataGrid.Columns>

        <DataGridTextColumn Header="ID" Binding="{Binding yourColumnItem}" />

    </DataGrid.Columns>
</DataGrid>

ViewModel:

public ObservableCollection<YourType> YourCollection { get; private set; }
public DelegateCommand checkCommand { get; private set; }


public YourViewModel(){
    checkCommand = new checkCommand(param => checkExecuted(param));
}

private void CheckExecuted(Object param)
{
        YourType item = param as YourType;

        YourCollection = new ObservableCollection<YourType>();
        YourCollection = model.ReadInvoices();  //you'll need a model class
        DoStuff(item.yourColumnItem);  //get the cell you want
}

App.xaml.cs

private YourViewModel _ViewModel;

public App()
{
   _ViewModel = new YourViewModel();
}

protected override void OnStartup(StartupEventArgs e)
{
        base.OnStartup(e);

        _MainWindow = new MainWindow();
        _MainWindow.DataContext = _ViewModel;
        _MainWindow.Show();
        //delete the startupuri row from App.xaml

}

你的DelegateCommand类:
using System;
using System.Windows.Input;

namespace yourSolution.ViewModel
{

public class DelegateCommand : ICommand
{
    private readonly Action<Object> _Execute; 
    private readonly Func<Object, Boolean> _CanExecute; 


    public DelegateCommand(Action<Object> execute) : this(null, execute) { }


    public DelegateCommand(Func<Object, Boolean> canExecute, Action<Object> execute)
    {
        if (execute == null)
        {
            throw new ArgumentNullException("execute");
        }

        _Execute = execute;
        _CanExecute = canExecute;
    }


    public event EventHandler CanExecuteChanged;


    public Boolean CanExecute(Object parameter)
    {
        return _CanExecute == null ? true : _CanExecute(parameter);
    }


    public void Execute(Object parameter)
    {
        _Execute(parameter);
    }


    public void RaiseCanExecuteChanged()
    {
        if (CanExecuteChanged != null)
            CanExecuteChanged(this, EventArgs.Empty);
    }
}
}

DatabaseModel.cs:

public ObservableCollection<YourType> ReadInvoices()
{
        Connect();  //write connection
        YourCollection.Clear();  //this is a private data part
        MySqlCommand cmd = new MySqlCommand(write your query);
        MySqlDataReader dr = cmd.ExecuteReader();

        YourCollection.Clear();
        YourType item = new YourType();

        while (dr.Read()){
          item.column = dr.GetInt32("columnName"); //or any other type
          YourCollection.Add(item);
        }

        dr.Close();
        Disconnect();

return YourCollection;
}

将您的命令绑定在 xaml 中的所选项上。这样它就会成为 CheckCommand 的参数:

Command="{Binding CheckCommand}" CommandParameter="{Binding ElementName=myGrid, Path=SelectedItem}"

我希望这个可以涵盖所有内容。当然,你需要EventHandlers来与App.xaml.cs通信,但我不知道你在处理单元格后想做什么。我只做过这三次,希望一切顺利。


谢谢您的帮助,但我似乎无法使其工作。我以为从数据网格中获取单元格会非常简单。 - thbl
1
-1 对于一个完全不必要和过于复杂的回答。95%的回答都是没有必要的...问题的作者只是想从他们的“DataGrid”中获取一个值,而不是学习MVVM...他们甚至没有添加MVVM标签或在问题中提到它。我们在这里的目的是帮助问题的作者,而不是不必要地使他们困惑。 - Sheridan
1
@Sheridan,如果您查看我的原始问题评论,您会发现我特别询问作者是否想要使用MVVM模式的答案。否则,在任何其他情况下,我都不会发布冗长的答案。伙计,我只是想帮忙提供一些代码,其中包含一个完全可重用的委托命令类。我本来不需要写下如何从数据库中读取内容的方法,只是为了澄清事情。顺便说一句,我自己在这里问过一些问题,其中一半的回复是像“你为什么需要这个?”等等。没有实际的帮助或代码。有趣的社区。 - Gábor Birkás
你说得很有道理,回想起来,我想我当时“因为回答过多”而对用户进行负面评价是有些愚蠢的...相比之下,“回答不足”问题的情况更加普遍。然而,我认为我的观点仍然站得住脚...如果你看一下提问者的解决方案,你应该也会这么认为。对于这个问题来说,这个回答确实太多了。话虽如此,我看到你是相对较新的用户,并且希望鼓励那些愿意花时间提供完整答案的用户,我已经完全改变了态度。所以,对于之前的行为表示歉意,对于好的回答和理由给予+1的支持。 - Sheridan
@Sheridan 非常感谢您!很高兴遇到珍视事物的人。现在我为自己之前对社区说的话感到内疚。我收回那些话,并且从现在开始会尽力以更恰当的方式回答问题。 - Gábor Birkás
我不相信这段代码实际上是有效的。传入的对象将始终返回 null..... - keelerjr12

3
请使用此方法,保证百分之百有效。
object item = dataGrid1.SelectedItem;
           string ID = (dataGrid1.SelectedCells[0].Column.GetCellContent(item) as TextBlock).Text;

0
YourDataGrid.SelectedIndex = X; 
DataRowView v = (DataRowView)YourDataGrid.SelectedItem;
TextBox1.Text = v[0].ToString();
TextBox2.Text = v[1].ToString();
TextBox3.Text = v[2].ToString();

如果你想在文本框中使用单元格的值,例如。

请考虑在您的答案中添加一些解释。 - Sunil

0
如果我理解正确的话,您想要从数据绑定到您的DataGrid的第二列的属性的选定行中获取值。然而,您展示给我们的代码并没有做到这一点。
private void CheckBox_Checked(object sender, RoutedEventArgs e)
{
    DataGrid row = (DataGrid)myGrid.SelectedItems[1]; // <--- 2nd item, not 2nd column!
    System.Windows.MessageBox.Show(row);
}

你的错误提示是...

索引超出了范围。必须为非负值且小于集合大小。
参数名: index

...因为当只有一个(或没有)项目被选中时,你尝试从SelectedItems集合中访问第二个项目。因此,你使用的索引(1)超出了范围。

然而,一旦你修复了这个错误,你会立即发现另一个错误提示,告诉你在DataGrid(你的row参数的类型)和DataGrid中的任何类型之间没有设置默认转换,这再次归咎于这行代码:

DataGrid row = (DataGrid)myGrid.SelectedItems[1];

这应该是...

YourDataType row = myGrid.SelectedItems[0];

...因为SelectedItems属性返回选定的集合中的项目。一旦您从所选行获取数据项,那么您所需要做的就是从中访问所需的属性...我相信您想要的是ItemID属性值:

int ItemId = row.ItemID;

我终于找到了!非常简单。DataRowView drv = (DataRowView)myGrid.SelectedItem; String result = (drv["CustomerID"]).ToString(); MessageBox.Show(result); - thbl

0

在 WPF 中,这个对我有效。

<DataGrid Name="dataGridShowStudents">
</DataGrid>

private void dataGridShowStudents_MouseDoubleClick(object sender, MouseButtonEventArgs e){
        DataRowView drv = (DataRowView)dataGridShowStudents.SelectedItem;
        string result = drv[0].ToString();
        MessageBox.Show(result);
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接