【问题标题】:Binding ObservableCollection to list将 ObservableCollection 绑定到列表
【发布时间】:2014-03-03 14:09:10
【问题描述】:

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

【问题讨论】:

  • Movie_DataGrid.ItemsSource = 检索信息; Retrievalinfo 是一个类而不是一个集合。我很惊讶编译。试试 Movie_DataGrid.ItemsSource = gridInfo;

标签: c# xml wpf binding datagrid


【解决方案1】:

首先,您提供的 xml 格式完美(元素没有结束标记的事实 - 没关系...以 /&gt; 结尾的标记(即:&lt;bla attributeName='value' /&gt;)被认为是关闭的,并且不需要结束标签。

第二 - 为什么不使用 linq to 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 的类型)。

【讨论】:

  • 您能否详细说明 linq to xml。这只是您使用的属性,例如 XElement、IEnumerable 等。另外,我想对 xml 说的是,在以前的问题和答案中,我看到大多数人都在使用保存到文件中的 xml,并且希望所有信息都存储在开始和结束标记之间,因此 GetElementsByTagName 对他们有用,但是不是我。
  • 也在您的 ObserableCollection 行中,movielist.Select....不提供“movieElement”选项。此外,在该序列之后,“movieElement =>”没有结束 ),除非“new Retrievalinfo()”在该行之外。您可以再次查看您的代码吗?
  • 关于 LINQ to xml - 谷歌吧!它比 DOMXml 简单和友好得多。关于 select - 你看到的是 lambda 表达式,它是一种编写匿名方法的方式。匿名方法获取一个参数(movieElement,其类型由编译器推断为 XElement),并返回新的 RetrieveInfo(这确实是命令的一部分)。
  • 好的。 lambda 表达式唯一的问题是它出错了,我无法编译。我从来没有使用过这些,所以我不知道最轻微的故障排除方法。它不应该有右括号吗?唯一出错的是新的 ObserableCollection,然后是 movieElement 参数,用于为关联变量赋值 (movie.Element.Attributes('title')....) 有什么建议吗?
  • 嗯,看起来不错(从我的手机上)...它不适用于 c#2.0 及更低版本(这意味着您需要 Visual Studio 2008 或更高版本),而且,您应该有using System.Linq; 在文件顶部(其他 using 语句的位置) - 否则编译器将无法识别 Select 方法...我希望它能解决您的问题
【解决方案2】:

首先;

我无法将列表绑定到 DataGrid

绑定到List 完全被接受,你可以做到。但是,您必须管理自己的 PropertyChanged 事件。这就是我们有 ObservableCollection 类的原因。当您将任何控件的 ItemSource 绑定到 ObservableCollection 时,视图会在发生更改时自动通知(添加/删除/修改,不再实例化)。所以你应该使用 ObservableCollection。

第二个;

我看到您在 Movie_List_SelectionChanged 方法中声明您的 gridInfo,这不好,因为 xaml 绑定机制将在您的 DataContext 中搜索 Property。 xaml 不会在那里找到 gridInfo。在你的 dataContext 中像这样在你的类中声明你的属性:

public ObservableCollection<Retrievalinfo> gridInfo { get; set; }

不要忘记在 DataContext 的构造函数中实例化它。并且不要忘记在您的 xaml 的代码中声明您的 DataContext。

最后,您已经在 xaml (ItemsSource="{Binding gridInfo}") 中声明了 ItemSource,因此无需在后面的代码 (Movie_DataGrid.ItemsSource = Retrievalinfo;) 中再次声明。

--编辑--
由于您的评论,我将尝试为您澄清一下。经典设计包含 3 件事:

  • XAML 文件、您的视图、信息的显示位置和方式。
  • 您将在其中声明 DataContext 的代码(.xaml.cs 文件)。
  • 您的数据上下文。它是您将在 XAML 中绑定的属性的 .cs。

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

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

DataContext = new MyDataContext();

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

希望这对您有所帮助。

【讨论】:

  • 你的意思是在我的 Retreivalinfo 类中存储我的变量。您提到 DataContext,是不是意味着我需要在 XMAL 中声明它?
  • 编辑了我的答案,请重新考虑阅读,希望对您有所帮助。
  • 是的,我知道列表上的绑定已关闭,所以我记得我有多个值。这也有帮助。但另一个问题。我的 Retivealinfo 类是否像 DataContext 一样工作?还是没有?
  • 没有。它是一个用于存储信息的“数据对象”。它们应该包含在 dataContext 中的 ObservableCollection 中。
  • 实际上 [0] 上的绑定有效,它可能不是最好的方法,但它确实有效
猜你喜欢
  • 2018-08-13
  • 2011-05-07
  • 2011-04-10
  • 2012-02-04
  • 2011-02-15
  • 2010-12-08
  • 2012-03-20
  • 2017-02-02
  • 1970-01-01
相关资源
最近更新 更多