我已经阅读了多个答案,但根本无法解决我的问题。我有一个程序从Web请求接收XML,在该请求中我只抓取该XML中的特定属性。单步执行时我可以看到一切正常,检索抓取正确的XML,排序并抓取正确的标签工作,然后将每个标签的内容分配给我在另一个类中工作的关联变量。此外,当单步执行时,“gridInfo”会显示我想要显示的每个值的列表。
我无法工作的是将列表绑定到DataGrid。如您所见,我创建了一个新的ObserableCollection类,其中存储了每个变量并调用该对象。我创建了该类的列表,并将XML中的值存储到该列表中。任何人都可以帮忙吗?
另外,当我查看我读过的XML时,你会注意到它不是正常格式,其中所有内容都包含在自己的开始和结束标记中,这就是为什么我必须使用DocumentElement以及GetElementsByTagName
代码背后:
// This action will seach the IMDb API for the associated infromation for the IMDBID that is tagged with the title you chose in the ListBox.
private void Movie_List_SelectionChanged(object sender, SelectionChangedEventArgs e)
{ // Grabs the IMDBID associated to the movie title selected to be used with the second API request.
var p = Movie_List.SelectedIndex;
string titleID = structholder[p].IMDBID;
string newurl = "http://www.omdbapi.com/?i=" + titleID + "&r=XML";
// Prepares 2nd API URL request to get data for chosen title.
// Creates a XML Document to store the xml data that was sent back by the API.
XmlDocument doc = new XmlDocument();
doc.Load(newurl);
// Creates a XML Noedlist to store the values that are going to be associated with the given attribute tag.
XmlNodeList movieList = doc.DocumentElement.GetElementsByTagName("movie");// GetElementsByTagName("root");
ObservableCollection<Retrievalinfo> test = new ObservableCollection<Retrievalinfo>();
List<Retrievalinfo> gridInfo = new List<Retrievalinfo>();
foreach (XmlNode node in movieList)
{
gridInfo.Add(new Retrievalinfo(){
title = node.Attributes["title"].Value.ToString(),
actors = node.Attributes["actors"].Value.Split(',').ToList(),
genre = node.Attributes["genre"].Value.ToString(),
rated = node.Attributes["rated"].Value.ToString(),
imdbRating = node.Attributes["imdbRating"].Value.ToString(),
released = node.Attributes["released"].Value.ToString(),
runtime = node.Attributes["runtime"].Value.ToString(),
});
}
Movie_DataGrid.ItemsSource = Retrievalinfo;
}
Retrivealinfo类:
namespace WpfApplication3
{
public class Retrievalinfo
{
public Retrievalinfo()
{
actors = new List<string>();
}
//Creating a list of info objects that will store all returned data for selected title.
public string title { get; set; }
public List<string> actors { get; set; }
public string genre { get; set; }
public string rated { get; set; }
public string imdbRating { get; set; }
public string released { get; set; }
public string runtime { get; set; }
}
}
XAML:
<ListBox x:Name="Movie_List" ItemsSource="{Binding listInfo}" Grid.ColumnSpan="2" HorizontalAlignment="Left" Height="287" Margin="20,107,0,0" VerticalAlignment="Top" Width="198" SelectionChanged="Movie_List_SelectionChanged" />
<Label Grid.ColumnSpan="2" Content="Movie List" HorizontalAlignment="Left" Height="30" Margin="70,72,0,0" VerticalAlignment="Top" Width="99" FontSize="16" FontFamily="Cooper Black" />
<DataGrid x:Name="Movie_DataGrid" Grid.ColumnSpan="2" HorizontalAlignment="Left" Margin="232,107,0,0" VerticalAlignment="Top" Height="198" Width="497" AutoGenerateColumns="True" ItemsSource="{Binding gridInfo}">
<DataGrid.Columns>
<DataGridTextColumn Header="Title" Binding="{Binding Path=title}"/>
<DataGridTextColumn Header="Main Actor 1" Binding="{Binding Path=actors[0]}"/>
<DataGridTextColumn Header="Main Actor 2" Binding="{Binding Path=actors[1]}"/>
<DataGridTextColumn Header="Main Actor 3" Binding="{Binding Path=actor[2]}"/>
<DataGridTextColumn Header="Genre" Binding="{Binding Path=genre}"/>
<DataGridTextColumn Header="Rated" Binding="{Binding Path=rated}"/>
<DataGridTextColumn Header="IMDB Rating" Binding="{Binding Path=imdbRating}"/>
<DataGridTextColumn Header="Released" Binding="{Binding Path=released}"/>
<DataGridTextColumn Header="Runtime" Binding="{Binding Path=runtime}"/>
</DataGrid.Columns>
</DataGrid>
我读入的XML:
<root response="True">
<movie title="Up in the Air" year="2009" rated="R" released="23 Dec 2009" runtime="109
min" genre="Drama, Romance" director="Jason Reitman" writer="Walter Kirn (novel), Jason
Reitman (screenplay), Sheldon Turner (screenplay)" actors="George Clooney, Vera Farmiga,
Anna Kendrick, Jason Bateman" plot="With a job that has him traveling around the country
firing people, Ryan Bingham leads an empty life out of a suitcase, until his company
does the unexpected: ground him." language="English" country="USA" awards="Nominated for
6 Oscars. Another 64 wins & 66 nominations."poster="http://ia.mediaimdb.com/images/M/MV5BMTI3MzYxMTA4NF5BMl5BanBnXkFtZTcwMD
E4ODg3Mg@@._V1_SX300.jpg" metascore="83" imdbRating="7.5" imdbVotes="215,961" imdbID="tt1193138" type="movie"/>
</root>
答案 0 :(得分:1)
首先,你提供的xml是完美形成的(事实上元素没有结束标记 - 可以......一个以/>
结尾的标记(即:<bla attributeName='value' />
)被认为是封闭的,不需要结束标记。
第二 - 为什么不使用linq到xml?它会使代码更简单,更易读:
// Prepares 2nd API URL request to get data for chosen title.
// Creates a XML Document to store the xml data that was sent back by the API.
var doc = XElement.Load(newurl);
// Creates a XML Noedlist to store the values that are going to be associated with the given attribute tag.
IEnumerable<XElement> movieList = doc.Descendants("movie");
ObservableCollection<Retrievalinfo> gridInfo = new ObservableCollection<Retrievalinfo>(movieList.Select(movieElement =>
new Retrievalinfo()
{
title = movieElement.Attribute("title").Value,
actors = movieElement.Attribute("actors").Value.Split(',').ToList(),
genre = movieElement.Attribute("genre").Value,
rated = movieElement.Attribute("rated").Value,
imdbRating = movieElement.Attribute("imdbRating").Value,
released = movieElement.Attribute("released").Value,
runtime = movieElement.Attribute("runtime").Value,
}));
最后 - 你误解了为什么首先使用ObservableCollection。 首先,绑定数据 - 只需绑定列表本身。
Movie_DataGrid.ItemsSource = gridInfo;
当您希望控件显示对列表所做的任何更改(任何添加,删除等),而不重新绑定它(这意味着完全重新加载),用户ObservableCollection。否则,您可以使用任何项目序列(即,实现IEnumerable的任何类型)。
答案 1 :(得分:0)
首先;
我无法工作的是将列表绑定到DataGrid
绑定到List
是完全可以接受的,你可以这样做。但是,您必须管理自己的PropertyChanged事件。这就是为什么我们有ObservableCollection类。当您将任何控件的ItemSource绑定到ObservableCollection时,View会在发生变化时自动通知(添加/删除/修改,不再实例化)。所以你应该使用ObservableCollection。
SECONDO;
我看到你在方法Movie_List_SelectionChanged
中声明了你的gridInfo,这是不好的,因为xaml Binding机制会在 DataContext 中搜索 Property 。 xaml在那里找不到gridInfo。在您的dataContext中声明您的类中的属性:
public ObservableCollection<Retrievalinfo> gridInfo { get; set; }
不要忘记在DataContext的构造函数中实例化它。而且不要忘记在xaml的代码后面声明你的DataContext。
最后,您已经在xaml(ItemsSource="{Binding gridInfo}"
)中声明了ItemSource,因此无需在后面的代码(Movie_DataGrid.ItemsSource = Retrievalinfo;
)中再次执行此操作。
<强> - 编辑 - 强>
由于您的评论,我将尝试为您澄清一些事情。经典设计会有三件事:
在你的情况下。你有你的XAML,顺便说一下这是不完全正确的(你不能说在actor [0]上绑定..你需要在datagrid中使用itemControl来生成那些列。我建议尝试一些教程网络。有很多简单的tuto可以帮助你提高对WPF的理解。
要继续,您还要在后面的构造函数中隐藏代码,通常,您应该只设置Datacontext。像这样:
DataContext = new MyDataContext();
然后,最后,在您的DataContext中,您应该声明在xaml中绑定的属性,并在构造函数中实例化它们。您还可以调用方法从任何数据库中获取信息(哪些方法也将在DataContext中。根据MVVM设计模式,View不应与模型通信。)
希望这有助于你。