C# WPF MVVM将DataTable绑定到DataGrid不显示数据

C# WPF MVVM将DataTable绑定到DataGrid不显示数据,c#,wpf,mvvm,datagrid,datatable,C#,Wpf,Mvvm,Datagrid,Datatable,我有一个简单的控件,它包含一个DataGrid,ItemsSource绑定到一个DataTable。当我填充DataTable时,我可以看到在DataGrid中添加了行,但没有显示任何数据。我没有为这个DataGrid使用任何特殊的样式(采用默认样式),唯一的设置是AutoGenerateColumn设置为True 在XAML中 <DataGrid AutoGenerateColumns="True" ItemsSource="{Binding TableResult}"/> 您还

我有一个简单的控件,它包含一个DataGrid,ItemsSource绑定到一个DataTable。当我填充DataTable时,我可以看到在DataGrid中添加了行,但没有显示任何数据。我没有为这个DataGrid使用任何特殊的样式(采用默认样式),唯一的设置是AutoGenerateColumn设置为True

在XAML中

<DataGrid AutoGenerateColumns="True" ItemsSource="{Binding TableResult}"/>

您还必须定义列:例如:

<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Source=TableResult}" >
            <DataGrid.Columns>
                <DataGridTextColumn Header="Name" Binding="{Binding col1}"/>
                <DataGridTextColumn Header="Surname" Binding="{Binding col2}"/>
                <DataGridTextColumn Header="Phone" Binding="{Binding col3}" />
            </DataGrid.Columns>
 </DataGrid>
public class YourViewModel
{
    public YourViewModel()
    {  
        FillTable();
    }
}


并确保您已经在视图模型中实现了
INotifyPropertyChanged
您需要调用DefaultView,下面是FillTable()方法中的更改


您的ItemsSource需要是对象列表,而不是DataRow/列。在任何情况下,在ViewModel上引用这些东西都会破坏MVVM

因此:


编辑:因为您事先对表本身一无所知,所以我建议您使用一个简单的字符串列表来生成行和列

大概是这样的:

    public List<List<string>> TableResult { get; set; } // raise property changed

必须将DataTable设置为引发属性更改。添加到它不会起任何作用;)

如果我添加以下内容,您的代码对我有效

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        FillTable();
        DataContext = this;
    }

填充DataGrid数据的工作示例:

    public MyViewModel()//constructor of MyViewModel
    {
        FillMyDataGrid();            
    }

    private DataTable employeeDataTable;

    public DataTable EmployeeDataTable
    {
        get { return employeeDataTable; }
        set
        {
            employeeDataTable = value;
            OnPropertyChanged("EmployeeDataTable");
        }
    }

    public FillMyDataGrid()
    {
            var _ds = new DataSet("Test");
            employeeDataTable = new DataTable();
            employeeDataTable = _ds.Tables.Add("DT");
            for (int i = 0; i < 50; i++)
            {
                //employeeDataTable.Columns.Add(i.ToString() + ".");
                employeeDataTable.Columns.Add(i.ToString());
            }
            for (int i = 0; i < 2; i++)
            {
                var theRow = employeeDataTable.NewRow();
                for (int j = 0; j < 50; j++)
                {                       
                        theRow[j] = "a";

                }
                employeeDataTable.Rows.Add(theRow);
            }
   }

我只是在努力解决这个问题,并找到了另一个我认为非常可靠的答案,其中包含了一些但不是所有其他人所贡献的东西。 Xaml(假定在页面级别设置了datacontext):


关键是首先显式地将绑定属性设置为null。我在WinForms中也发现了这一点。

您是否在任何位置分配了DataContext?是的,它是在应用程序中合并的资源字典中完成的。XAML查看我的答案,您必须以正确的方式设置DataContext DataContext不是问题,其他每个控件都绑定良好。此外,行被添加到数据网格中,但没有显示任何内容。无需放置AutoGenerateColumns=“False”事实上,无需定义列,我也不想这样做,因为我的数据表是在MVVM上下文中动态生成的,我无法访问GUI元素。但是,我们可以看到,与ItemsSource的绑定在某种程度上是有效的,因为行被添加到DataGrid中,这是我在其他文章中读到的,但是如何处理动态数据呢?我不知道运行前的列名,也不知道它们的编号……但动态数据是什么意思?如果确定有多少列,只需将列名绑定到ViewModel中的变量即可。其余的值都可以这样做,我的意思是,数据集可以有任意数量的任意名称的列。我无法将我的数据表示为已定义的模型,因为我事先不知道它。更新了我的答案,@GuillaumeA“如果您相信MVVM允许,您可以保留您的数据表”事实上我不知道,我只是将数据表视为一个数据容器,所以我不明白为什么它应该在视图中填充。。。但我又是谁呢;)但是,我认为您发现了我的问题,在我更新datatable时从未引发property changed事件这一事实可能是解决方案,我将尝试一下。太棒了!
    public List<List<string>> TableResult { get; set; } // raise property changed
        List<string> columns = new List<string>() { "Col1", "Col2", "Col3", "Col4" };

        List<string> row1 = new List<string>() { "a", "b", "c", "d" };
        List<string> row2 = new List<string>() { "w", "x", "y", "z" };
        List<List<string>> table = new List<List<string>>(){columns,row1,row2};
        TableResult = table;
public class ListToTables : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var list =  value as List<List<string>>;
        var headers = list.First();
        DataTable dt = new DataTable();

        foreach (string header in headers)
        {
            dt.Columns.Add(header);
        }
        foreach (List<string> row in list.Skip(1))
        {
            int index = 0;
            DataRow r = dt.NewRow();
            foreach (string col in row)
            {
                r[index++] = col;
            }
            dt.Rows.Add(r);
        }
        return dt;

    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}
        <local:ListToTables x:Key="listToTables"></local:ListToTables>
    <DataGrid ItemsSource="{Binding TableResult,Converter={StaticResource listToTables}}" >
   DataTable tempDataTable = new DataTable();
   DataColumn c = new DataColumn();
   c.ColumnName = "Col1";
   tempDataTable.Columns.Add(c);

   c = new DataColumn();
   c.ColumnName = "Col2";
   tempDataTable.Columns.Add(c);

   DataRow row1 = tempDataTable.NewRow();
   row1["Col1"] = "Blue";
   row1["Col2"] = "12";;
   tempDataTable.Rows.Add(row1);

   DataRow row2 = tempDataTable.NewRow();
   row2["Col1"] = "Red";
   row2["Col2"] = "18";
   tempDataTable.Rows.Add(row2);

   DataRow row3 = tempDataTable.NewRow();
   row3["Col1"] = "Yellow";
   row3["Col2"] = "27";
   tempDataTable.Rows.Add(row3);
   this.DataTable = tempDataTable;
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        FillTable();
        DataContext = this;
    }
    public MyViewModel()//constructor of MyViewModel
    {
        FillMyDataGrid();            
    }

    private DataTable employeeDataTable;

    public DataTable EmployeeDataTable
    {
        get { return employeeDataTable; }
        set
        {
            employeeDataTable = value;
            OnPropertyChanged("EmployeeDataTable");
        }
    }

    public FillMyDataGrid()
    {
            var _ds = new DataSet("Test");
            employeeDataTable = new DataTable();
            employeeDataTable = _ds.Tables.Add("DT");
            for (int i = 0; i < 50; i++)
            {
                //employeeDataTable.Columns.Add(i.ToString() + ".");
                employeeDataTable.Columns.Add(i.ToString());
            }
            for (int i = 0; i < 2; i++)
            {
                var theRow = employeeDataTable.NewRow();
                for (int j = 0; j < 50; j++)
                {                       
                        theRow[j] = "a";

                }
                employeeDataTable.Rows.Add(theRow);
            }
   }
<DataGrid ItemsSource="{Binding EmployeeDataTable}"/>
public class YourViewModel
{
    public YourViewModel()
    {  
        FillTable();
    }
}
<DataGrid ItemsSource="{Binding Findings}" />
Findings = null;
Findings = dataTable.DefaultView