1

我使用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,但只有标题。我没有得到行的价值。在此示例中,有行,但没有值。

在此处输入图像描述

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

4

1 回答 1

1

除了起始数据来自 SPARQL 查询之外,这个问题与 dotNetRDF 并没有太大关系,但实际上是关于使用is a和使用DataGrid时的行为方式。ItemsSourceDataTableAutoGenerateColumns

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

因此,实际上要正确显示值需要我们创建一个DataTemplate供我们使用的列。但是,当您想使用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类型,这只是使用重命名为更具描述性的TemplateColumns 将 WPF DataGrid 绑定到 DataTable的答案中的类。

我们不能直接使用DataGridTemplateColumn的原因是,当为每个列绑定DataTable模板时,传递的是整行而不是特定列的值,所以我们需要扩展类以便只绑定特定的列值,所以我们的模板格式INode行中该列的实际值,而不是整行。

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

<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>

请注意,我还在这里定义了一个值转换器,这MethodToValueConverter取自Bind to a method in WPF? 并允许我们简单地获取任意类型的方法调用的结果并将其用作我们的显示值。在这里,我们模板的配置只是调用ToString()了底层INode实例。

实现所有这些事情后,我运行您的示例查询,并在我的DataGrid:

在此处输入图像描述

您可以在https://bitbucket.org/rvesse/so-23711774找到我使用的所有代码

您可以使用这种基本方法来构建一个更强大的渲染,INode其中包含您认为合适的尽可能多的视觉花里胡哨。

旁注

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

其次,dotNetRDFSparqlResultSet类实际上已经定义了一个明确的强制转换,DataTable因此您不需要手动将其转换为DataTable您自己,除非您想控制DataTable例如的结构

DataTable table = (DataTable) results;
于 2014-05-19T14:51:03.160 回答