【问题标题】:Wpf DataGrid data binding with arbitrary colums and rows具有任意列和行的 Wpf DataGrid 数据绑定
【发布时间】:2015-11-03 10:59:31
【问题描述】:

对于我的一个项目,我正在尝试从文件(例如 *.csv)加载数据并将其显示在 DataGrid 中。文件的格式没有给出。例如,列数和行数因文件而异。因此,任务是将通用数据表加载到程序中并在DataGrid 中查看。

我的第一次尝试是使用DataTable 并以某种方式将其绑定到DataGrid。然而,经过一段时间的搜索,我读到使用DataTable 不是最好的解决方案,应该使用数据模型。不幸的是,网络中的大多数示例都使用具有固定数据列的数据。此外,我无法让DataGridDataTable 之间的绑定正常工作。能够对两端的数据进行更改会非常好:DataGrid(就像用户那样)和底层数据结构(就像代码那样)。

请有人解释一下,为什么不应该使用DataTable?应该使用什么来实现上述行为?

数据加载本身应该没问题,但是如何将数据表以灵活的方式存储、处理和绑定到DataGridis。

以下代码类型有效。但是,它似乎没有响应对数据的任何更改,例如添加行或列,但 DataTable 包含正确的数据。

<DataGrid x:Name="myDataGrid" AutoGenerateColumns="True"
 x:Name="myDataGrid1" AutoGenerateColumns="True" ItemsSource="{Binding myDataTable}"  />
DataTable myDataTable  { get; private set; }
...
myDataGrid.DataContext = this;
LoadData();
myDataGrid.ItemsSource = myDataTable.DefaultView;

我非常感谢任何帮助!提前致谢!

【问题讨论】:

  • 感谢您的回复。该主题中提供的解决方案实际上与我的“示例”相同。如果单元格的内容发生变化是可以的,但如果行或列发生变化则失败......

标签: c# wpf xaml binding datagrid


【解决方案1】:

尝试将 ItemsSource 设置为 BindingListCollectionView。到目前为止,我运气不错。我使用这些扩展方法:

  public static BindingListCollectionView GetCollectionView(this DataTable table)
        {
            return new BindingListCollectionView(table.DefaultView);
        }



 public static DataTable GetDataTable(this BindingListCollectionView view)
    {
        var dataView = view.SourceCollection as DataView;
        if (dataView != null)
        {
            return dataView.Table;
        }

        return null;
    }

在您的代码中使用它,例如:

myDataGrid.ItemsSource = myDataTable.GetCollectionView();

var view = myDataGrid.ItemsSource as BindingListCollectionView;
var table = view.GetDataTable();

您应该能够像往常一样使用 DataTable 对象,保留网格所做的所有更改。

【讨论】:

  • 感谢您的建议。但是使用BindingListCollectionView 而不是DataTable(或DataTable.DefaulView)进行绑定没有任何区别......
【解决方案2】:

经过一些进一步的调查,我找到了一个适合我的解决方案。但是,感觉有点奇怪,不是最好的解决方案,但我可以忍受。再次感谢您的努力,这对我帮助很大。

这个想法是每当通过取消设置/设置GridViewDataContext 添加/删除列时刷新GridView。我使用DataTable.Columns.CollectionChanged 事件来实现此行为。

现在,几乎一切都很好。剩下的唯一问题是用户通过GridView 添加新行时(单击最后一个空行并输入数据时)。不过,这只是一个小问题,因为绑定的 DataTable 已正确更新,只有第二个 GridView(在下面的示例中)未正确显示。

问题仍然存在,DataTable 的使用是否是最佳解决方案。如果DataContext的重置对大数据集造成麻烦需要测试...

这是一个关于问题和解决方案的完整示例:

XAML:

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         x:Class="WpfApplicationTest.MainWindow"
         Title="DataGrid and DataTable Test" Height="500" Width="800">
    <DockPanel>
        <StackPanel Orientation="Horizontal" DockPanel.Dock="Top">
            <Button Click="ButtonRefresh_Click">Refresh Grids</Button>
            <Button Click="ButtonAddRow_Click">Add Row</Button>
            <Button Click="ButtonAddCol_Click">Add Col</Button>
            <Button Click="ButtonEdit_Click">Edit Randomly</Button>
        </StackPanel>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <DataGrid x:Name="myDataGrid0" Grid.Column="0" AutoGenerateColumns="True" ItemsSource="{Binding}" />
            <DataGrid x:Name="myDataGrid1" Grid.Column="1" AutoGenerateColumns="True" ItemsSource="{Binding}" />
        </Grid>
    </DockPanel>
</Window>

代码背后:

using System;
using System.Data;
using System.Windows;

namespace WpfApplicationTest
{
    public partial class MainWindow : Window
    {
        private DataTable myDataTable;
        private Random myRandom = new Random();

        public MainWindow()
        {
            InitializeComponent();

            myDataTable = new DataTable();

            // create some datatable
            myDataTable.Columns.Add("First");
            myDataTable.Columns.Add("Second");
            myDataTable.Rows.Add(myRandom.Next(100).ToString(), myRandom.Next(100).ToString());
            myDataTable.Rows.Add(myRandom.Next(100).ToString(), myRandom.Next(100).ToString());

            myDataGrid0.DataContext = myDataTable;
            myDataGrid1.DataContext = myDataTable;

            myDataTable.Columns.CollectionChanged += Columns_CollectionChanged;
        }

        private void Columns_CollectionChanged(object sender, System.ComponentModel.CollectionChangeEventArgs e)
        {
            // refresh the grid views by reseting the data context after the columns have changed
            myDataGrid0.DataContext = null;
            myDataGrid0.DataContext = myDataTable;
            myDataGrid1.DataContext = null;
            myDataGrid1.DataContext = myDataTable;
        }

        private void ButtonRefresh_Click(object sender, RoutedEventArgs e)
        {
            // refresh the grid views by reseting the data context
            myDataGrid0.DataContext = null;
            myDataGrid0.DataContext = myDataTable;
            myDataGrid1.DataContext = null;
            myDataGrid1.DataContext = myDataTable;
        }

        private void ButtonAddRow_Click(object sender, RoutedEventArgs e)
        {
            // add rows with random content
            DataRow row = myDataTable.NewRow();
            for (int i = 0; i < row.ItemArray.Length; ++i)
                row[i] = myRandom.Next(100);
            myDataTable.Rows.Add(row);
        }

        int rowcount = 0;
        private void ButtonAddCol_Click(object sender, RoutedEventArgs e)
        {
            // add columns with random content
            myDataTable.Columns.Add("New" + rowcount.ToString());
            foreach (DataRow row in myDataTable.Rows)
                row["New" + rowcount.ToString()] = myRandom.Next(100);
            ++rowcount;
        }

        private void ButtonEdit_Click(object sender, RoutedEventArgs e)
        {
            // randomly change some data table values
            myDataTable.Rows[myRandom.Next(myDataTable.Rows.Count)][myRandom.Next(myDataTable.Columns.Count)] = myRandom.Next(100);
        }
    }
}

【讨论】:

    猜你喜欢
    • 2011-09-29
    • 1970-01-01
    • 2020-09-27
    • 2011-02-04
    • 1970-01-01
    • 2011-05-06
    • 2012-08-17
    • 2011-06-15
    相关资源
    最近更新 更多