将ObservableCollection绑定到列表

时间:2014-03-03 14:09:10

标签: c# xml wpf binding datagrid

我已经阅读了多个答案,但根本无法解决我的问题。我有一个程序从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>    

2 个答案:

答案 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;

当您希望控件显示对列表所做的任何更改(任何添加,删除等),而不重新绑定它(这意味着完全重新加载),用户Obs​​ervableCollection。否则,您可以使用任何项目序列(即,实现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文件,您的视图,信息的显示位置和方式。
  • 您将在其中声明DataContext的代码(.xaml.cs文件)。
  • 您的DataContext。它是.cs,您将拥有要在XAML中绑定的属性。

在你的情况下。你有你的XAML,顺便说一下这是不完全正确的(你不能说在actor [0]上绑定..你需要在datagrid中使用itemControl来生成那些列。我建议尝试一些教程网络。有很多简单的tuto可以帮助你提高对WPF的理解。

要继续,您还要在后面的构造函数中隐藏代码,通常,您应该只设置Datacontext。像这样:

DataContext = new MyDataContext();

然后,最后,在您的DataContext中,您应该声明在xaml中绑定的属性,并在构造函数中实例化它们。您还可以调用方法从任何数据库中获取信息(哪些方法也将在DataContext中。根据MVVM设计模式,View不应与模型通信。)

希望这有助于你。