我使用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,但只有标题。我没有得到行的价值。在这个例子中有行,但没有值。
我的问题在哪里?非常感谢你的帮助:)
答案 0 :(得分:1)
除了起始数据来自SPARQL查询之外,这个问题与dotNetRDF没什么关系,但实际上是DataGrid
ItemsSource
为DataTable
时AutoGenerateColumns
的行为方式{使用{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
中获得以下内容:
您可以在https://bitbucket.org/rvesse/so-23711774
找到我使用的所有代码您可以使用这种基本方法构建更加强大的SparqlResultSet
渲染,并使用您认为合适的视觉铃声和口哨。
与此答案相关的几个注释,首先,如果您发布了代码的最小完整示例而不仅仅是部分XAML和代码片段,那么生成起来要容易得多。
其次,dotNetRDF DataTable
类实际上已经定义了explicit cast到DataTable
,因此您不需要自己手动将其翻译为DataTable
,除非您想要控制DataTable table = (DataTable) results;
的结构,例如
{{1}}