数据将DataGrid绑定到具有嵌套类的对象

时间:2016-12-07 20:10:23

标签: c# json wpf xaml datagrid

所以我有一个运行查询并返回JSON响应的api调用。由于JSON响应的结构,我创建了一个类,我可以使用Json.Net直接反序列化返回。这是示例类:

public class QuerySet
{
    public List<Column> Columns { get; set; }
    public class Column
    {
        public List<string> Name { get; set; }
    }
    public List<RowSet> Rows { get; set; }
    public class RowSet
    {
        public List<DataSet> Row { get; set; }
        public class DataSet
        {
            public List<string> Data { get; set; }
        }
    }
}

现在,单个API调用可以包含多个查询集,因此对于每个返回,我生成一个查询集列表,然后我想将DataGrid数据绑定到每个集合。这是我目前在窗口后面的代码中的示例:

    public List<DataGrid> QueryResults;

    public QueryResultsWindow(string _name, JObject _returns)
    {
        InitializeComponent();
        QueryNameText.Text = _name;
        QueryResults = new List<DataGrid>();

        JArray sets = (JArray)_returns.SelectToken("$..Set");

        foreach(JObject set in sets)
        {
            DataGrid dg = new DataGrid();
            QuerySet s = new QuerySet();
            s = JsonConvert.DeserializeObject<QuerySet>(set.ToString());

            dg.ItemsSource = s.Rows;

            QueryResults.Add(dg);
        }

        ResultsListBox.ItemsSource = QueryResults;
    }

您可能会看到这里的问题是,对于每个特定的DataGrid,我希望将Column Headers绑定到Name属性,并将数据从Data属性填充。

以下是我目前在窗口中设置XAML的方法:

   <DockPanel>
        <StackPanel Orientation="Horizontal" DockPanel.Dock="Top" VerticalAlignment="Top">
            <TextBlock x:Name="QueryNameText" Margin="5"></TextBlock>
            <Button Content="Export Results" Click="Button_Click" Margin="5"></Button>
        </StackPanel>
        <ListBox DockPanel.Dock="Top" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="3" Name="ResultsListBox">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <DataGrid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ItemsSource="{Binding UpdateSourceTrigger=PropertyChanged}" CanUserAddRows="False" IsReadOnly="True" SelectionUnit="Cell">
                        <DataGrid.Columns>
                            <DataGridTextColumn Header="{Binding Name}"></DataGridTextColumn>
                        </DataGrid.Columns>
                    </DataGrid>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </DockPanel>

我知道如果我想为每种可能的返回类型创建一个自定义类,这将更容易。但是,考虑到数百种潜在的返回类型,这似乎不太可行。我已经尝试过使用DataTables,我已经尝试在XAML中的ListBox中设置DataGrid,但我可能没有正确实现这一点,最后决定尝试创建DataGrids列表然后绑定到那些。

我可以使用一些帮助。

谢谢!

1 个答案:

答案 0 :(得分:1)

在经历了一些搞乱之后。这是我想出的答案。

我使用了上面的查询集类,并添加了一个在QuerySet类中构建DataTable的方法:

   public class QuerySet
    {
        public DataTable BindableTable { get; private set; }
        public static List<string> ColumnName { get; private set; }
        public static List<RowSet.DataSet> RowsSet { get; private set; }

        public List<Column> Columns { get; set; }
        public class Column
        {
            private List<string> _name;

            public List<string> Name
            {
                get { return _name; }
                set { _name = value; ColumnName = _name; }
            }


        }
        public List<RowSet> Rows { get; set; }

        public class RowSet
        {
            private List<DataSet> _row;

            public List<DataSet> Row
            {
                get { return _row; }
                set { _row = value; RowsSet = _row; }
            }

            public class DataSet
            {
                public List<string> Data { get; set; }
            }
        }

        public void GetDataGridTable()
        {
            DataTable table = new DataTable();
            foreach(string name in ColumnName)
            {
                table.Columns.Add(name);
            }
            foreach(RowSet.DataSet set in RowsSet)
            {
                DataRow row = table.NewRow();
                int counter = 0;
                foreach(string item in set.Data)
                {
                    row[counter] = item;
                    counter++;
                }
                table.Rows.Add(row);
            }

            BindableTable = table;
        }
    }

我添加了几个访问器,以便更容易地获得嵌套位,并从那里构建了一个DataTable。在我的弹出窗口后面的代码中,我创建了一个Observable DataGrids集合,并根据QuerySet将每个Grid的DataContext设置为DataView:

    public ObservableCollection<DataGrid> QueryResults;
    public event PropertyChangedEventHandler PropertyChanged;

    public QueryResultsWindow(string _name, JObject _returns)
    {
        InitializeComponent();
        QueryNameText.Text = _name;
        QueryResults = new ObservableCollection<DataGrid>();

        JArray sets = (JArray)_returns.SelectToken("$..Set");

        foreach(JObject set in sets)
        {
            DataGrid dg = new DataGrid();
            QuerySet s = new QuerySet();
            s = JsonConvert.DeserializeObject<QuerySet>(set.ToString());

            s.GetDataGridTable();
            DataView newView = new DataView(s.BindableTable);
            dg.ItemsSource = newView;
            dg.CanUserAddRows = false;
            dg.CanUserDeleteRows = false;
            QueryResults.Add(dg);
        }

        ResultsListBox.ItemsSource = QueryResults;
    }

然后我的弹出窗口中的XAML非常简单:

<DockPanel>
    <StackPanel Orientation="Horizontal" DockPanel.Dock="Top" VerticalAlignment="Top">
        <TextBlock x:Name="QueryNameText" Margin="5"></TextBlock>
        <Button Content="Export Results" Click="Button_Click" Margin="5"></Button>
    </StackPanel>
    <ListBox DockPanel.Dock="Top" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="3" Name="ResultsListBox" ItemsSource="{Binding QueryResults}">
    </ListBox>
</DockPanel>

显然这不是最优雅的解决方案。即使只是在这里查看它,我也可以在QuerySet类中轻松创建DataView,而不是在后面的代码中进行转换。所以,虽然答案并不完美,但它现在仍然有用。