SPARQL导致WPF(绑定DataGrid)

时间:2014-05-17 13:15:51

标签: wpf datagrid sparql dotnetrdf

我使用dotnetrdf,我想在WPF中显示查询结果。这是我在ViewModel中的功能。我有DataTable,我在下面的视图中使用它。

        //Results
        SparqlResultSet results;
        DataTable table;
        //Define a remote endpoint
        //Use the DBPedia SPARQL endpoint with the default Graph set to DBPedia
        SparqlRemoteEndpoint endpoint = new SparqlRemoteEndpoint(new Uri("http://dbpedia.org/sparql"), "http://dbpedia.org");

        //Make a SELECT query against the Endpoint
        results = endpoint.QueryWithResultSet("PREFIX dbo: <http://dbpedia.org/ontology/> PREFIX : <http://dbpedia.org/resource/> SELECT ?film ?producerName WHERE {    ?film dbo:director :Andrzej_Wajda .    ?film dbo:producer ?producerName . }");
        foreach (SparqlResult result in results)
        {
           Console.WriteLine(result.ToString());
        }

        table = new DataTable();
        DataRow row;

        switch (results.ResultsType)
        {
            case SparqlResultsType.VariableBindings:
                foreach (String var in results.Variables)
                {
                    table.Columns.Add(new DataColumn(var, typeof(INode)));
                }

                foreach (SparqlResult r in results)
                {
                    row = table.NewRow();

                    foreach (String var in results.Variables)
                    {
                        if (r.HasValue(var))
                        {
                            row[var] = r[var];
                        }
                        else
                        {
                            row[var] = null;
                        }
                    }
                    table.Rows.Add(row);
                }
                break;
            case SparqlResultsType.Boolean:
                table.Columns.Add(new DataColumn("ASK", typeof(bool)));
                row = table.NewRow();
                row["ASK"] = results.Result;
                table.Rows.Add(row);
                break;

            case SparqlResultsType.Unknown:
            default:
                throw new InvalidCastException("Unable to cast a SparqlResultSet to a DataTable as the ResultSet has yet to be filled with data and so has no SparqlResultsType which determines how it is cast to a DataTable");
        }

在WPF中,我使用代码:

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

绑定工作非常好,最后我得到动态创建的列和DataGrid,但只有标题。我没有得到行的价值。在这个例子中有行,但没有值。

enter image description here

我的问题在哪里?非常感谢你的帮助:)

1 个答案:

答案 0 :(得分:1)

除了起始数据来自SPARQL查询之外,这个问题与dotNetRDF没什么关系,但实际上是DataGrid ItemsSourceDataTableAutoGenerateColumns的行为方式{使用{1}}。

基本问题是DataGrid不知道如何显示任意数据类型,它只为自动生成的列生成DataGridTextColumn。不幸的是,这仅支持String应用了显式IValueConverter AFAIK的值ToString(),它不会调用DataTemplate,因为转换预计会有两种方式,因此您会看到空列(感谢this question解释这一点。)

因此,实际上要正确显示值需要我们为要使用的列创建AutoGenerateColumns。但是,如果您想使用AutoGeneratingColumns,则需要为<DataGrid ItemsSource="{Binding Table}" AutoGenerateColumns="True" AutoGeneratingColumn="AutoGeneratingColumn" /> 事件添加处理程序,如下所示:

private void AutoGeneratingColumn(object sender, System.Windows.Controls.DataGridAutoGeneratingColumnEventArgs e)
{
    if (e.PropertyType != typeof (INode)) return;
    DataTableDataGridTemplateColumn column = new DataTableDataGridTemplateColumn();
    column.ColumnName = e.PropertyName;
    column.ClipboardContentBinding = e.Column.ClipboardContentBinding;
    column.Header = e.Column.Header;
    column.SortMemberPath = e.Column.SortMemberPath;
    column.Width = e.Column.Width;
    column.CellTemplate = (DataTemplate) Resources["NodeTemplate"];

    e.Column = column;
}

接下来,您需要添加事件处理程序的实现,以便为每个自动生成的列应用适当的列类型,如下所示:

DataTableDataGridTemplateColumn

请注意,此处使用了特殊的DataTable类型,这只是将Binding WPF DataGrid to DataTable using TemplateColumns的答案重命名为更具描述性的类。

我们不能直接使用DataGridTemplateColumn的原因是当绑定INode时,每个列的模板都传递整行而不是特定的列值,所以我们需要扩展类为了只绑定特定的列值,我们的模板格式化行中该列的实际<Window.Resources> <sparqlResultsDataGridWpf:MethodToValueConverter x:Key="MethodToValueConverter" /> <DataTemplate x:Key="NodeTemplate" DataType="rdf:INode"> <TextBlock Text="{Binding Converter={StaticResource MethodToValueConverter}, ConverterParameter='ToString'}"/> </DataTemplate> </Window.Resources> 值,而不是整行。

最后,我们需要定义我们在XAML中引用的模板,以便我们的列格式适当:

MethodToValueConverter

请注意,我还在这里定义了一个值转换器,这个ToString()取自Bind to a method in WPF?的答案,并允许我们简单地对任意类型的方法调用结果并使用这是我们的显示价值。在这里,我们模板的配置只需在基础INode实例上调用DataGrid

实现所有这些功能后,我运行您的示例查询,并在INode中获得以下内容:

enter image description here

您可以在https://bitbucket.org/rvesse/so-23711774

找到我使用的所有代码

您可以使用这种基本方法构建更加强大的SparqlResultSet渲染,并使用您认为合适的视觉铃声和口哨。

附注

与此答案相关的几个注释,首先,如果您发布了代码的最小完整示例而不仅仅是部分XAML和代码片段,那么生成起来要容易得多。

其次,dotNetRDF DataTable类实际上已经定义了explicit castDataTable,因此您不需要自己手动将其翻译为DataTable,除非您想要控制DataTable table = (DataTable) results; 的结构,例如

{{1}}