绑定到从XML填充的ObservableCollection不起作用

时间:2022-07-17 03:46:23

Using Blend.

I am trying to bind either a GridView or TextBlock to an Observable collection. The observable collection gets its data from an XML file. My test program runs, but no data appears in the GridView or the TextBlock when I press the 'Show Sentence' button.

我试图将GridView或TextBlock绑定到Observable集合。可观察集合从XML文件中获取其数据。我的测试程序运行,但是当我按下“显示句子”按钮时,GridView或TextBlock中没有数据出现。

My XML file:

我的XML文件:

(Simlpified from a large and complex file which works OK in a Visual Studio console project)

(从一个在Visual Studio控制台项目中正常运行的大而复杂的文件中模拟)

<Book ISBN ="9144252184178">
  <Title>
    <TitleLine>Title First Line</TitleLine>
    <TitleLine>Title Second Line</TitleLine>
  </Title>
  <Authors>
    <Author>Some Body</Author>
    <Author>No Body</Author>
  </Authors>
  <Pages>
    <Page PageNumber ="1">
      <Sentences>
        <Sentence SentenceID = "1">
          <SentenceText>Once there was a giant </SentenceText>
          <SentenceFileName>9144252184178.1.1</SentenceFileName>
          <SentenceWords>
            <SentenceWord Start = "" Part = "">once</SentenceWord>
            <SentenceWord Start = "" Part = "">there</SentenceWord>
            <SentenceWord Start = "" Part = "">was</SentenceWord>
            <SentenceWord Start = "" Part = "">a</SentenceWord>
            <SentenceWord Start = "" Part = "">giant</SentenceWord>
          </SentenceWords>
        </Sentence>
        <Sentence SentenceID = "2">
          <SentenceText>Every day, etc</SentenceText>
          <SentenceFileName>9144252184178.1.2</SentenceFileName>
          <SentenceWords>
            <SentenceWord Start = "" Part = "">every</SentenceWord>
            <SentenceWord Start = "" Part = "">day</SentenceWord>
            <SentenceWord Start = "" Part = "">etc</SentenceWord>
          </SentenceWords>
        </Sentence>
      </Sentences>
    </Page>
  </Pages>
</Book>

MainPage.xaml:

(Showing a couple of the many ways I have unsuccessfully tried to bind to the ObservableCollection)

(显示我尝试绑定到ObservableCollection失败的许多方法中的几种)

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
  <StackPanel>
    <Button x:Name="button" Content="Show Sentence" Click="button_Click"/>
    <GridView Background="Bisque" ItemsSource="{x:Bind ThisSentence}">
      <GridView.ItemTemplate>
        <DataTemplate x:DataType="data:Sentences">
          <StackPanel Background="AliceBlue">
            <TextBlock Text="Sentence"/>
            <TextBlock Text="{x:Bind SentenceID}"/>
            <TextBlock Text="{x:Bind SentenceText}"/>
           </StackPanel>
         </DataTemplate>
      </GridView.ItemTemplate>
    </GridView>
    <Border Background="LightBlue">
      <TextBlock Text="{Binding ThisSentence.SentenceID, Mode=OneWay}"/>
    </Border>
  </StackPanel>
</Grid>  

MainPage.xaml.cs:

namespace ImportFromXML
{
    public sealed partial class MainPage : Page
    {
        private ObservableCollection<Book> thisSentence_;
        public ObservableCollection<Book> ThisSentence
        {
            get { return thisSentence_; }
            set { thisSentence_ = value; }
        }

        public MainPage()
        {
            this.InitializeComponent();
        }

        private void button_Click(object sender, RoutedEventArgs e)
        {
           var newTask = Task.Run(() => thisSentence_ = SentenceManager.GetSentence("0","0")) ;
           DataContext = ThisSentence;
        }
    }
}

Book.cs:

(Here are my classes and my SentenceManager. The SentenceManager Linq code works against my XML when run in a VS Console project.)

(这是我的类和我的SentenceManager。当在VS Console项目中运行时,SentenceManager Linq代码对我的XML起作用。)

public class Book
{
    public string ISBN { get; set; }
    public IList<Title> title = new List<Title>();
    public IList<Authors> authors = new List<Authors>();
    public IList<Pages> pages = new List<Pages>();
}

public class Title
{
    public string TitleLine { get; set; }
}

public class Authors
{
    public string AuthorName { get; set; }
}

public class Pages
{
    public string PageNumber { get; set; }
    public IList<Sentences> sentences = new List<Sentences>();
    public IList<Contents> contents = new List<Contents>();
 }

public class Sentences
{
    public string SentenceID { get; set; }
    public string SentenceText { get; set; }
    public string SentenceFileName { get; set; }
    public IList<SentenceWords> sentenceWords = new List SentenceWords>();
}

public class SentenceWords
{
    public string SentenceWord { get; set; }
    public string Ending { get; set; }
    public string Parent { get; set; }
}


public class SentenceManager
{
    public static ObservableCollection<Book> GetSentence(string pageNumber, string sentenceID)
    {

        XDocument xdoc = XDocument.Load(@"C:\Users\Richard\Documents\ImportFromXML\book.xml");
        List<Book> sentence = (from bk in xdoc.Elements("Book")
                               select new Book
                               {
                                 pages = (from pag in bk.Element("Pages").Elements("Page")
                                          where (string)pag.Attribute("PageNumber") == pageNumber
                                          select new Pages
                                           {
                                             sentences = (from sen in pag.Element("Sentences").Elements("Sentence")
                                                          where (string)sen.Attribute("SentenceID") == sentenceID
                                                          select new Sentences
                                                          {
                                                            SentenceID = sen.Attribute("SentenceID").Value,
                                                            SentenceText = sen.Element("SentenceText").Value,
                                                            SentenceFileName = sen.Element("SentenceFileName").Value,
                                                          }).ToList(),
                                            }).ToList(),
                               }).ToList();

        ObservableCollection <Book> Sentence = new ObservableCollection<Book>(sentence);
        return Sentence;
    }
}

In my program I have to bind a number of controls to various parts of my xml data, so this is just one example.

在我的程序中,我必须将许多控件绑定到我的xml数据的各个部分,所以这只是一个例子。

I am a bit of a novice, so please don't make your advice too cryptic or I may not understand! Thanks for any help you can give me.

我是一个新手,所以请不要让你的建议太神秘,或者我可能不明白!感谢你给与我的帮助。

1 个解决方案

#1


0  

First of all, when you bind to the ThisSentence property by x:Bind like

首先,当你通过x绑定到ThisSentence属性时:Bind like

ItemsSource="{x:Bind ThisSentence}"

it is not necessary to set the DataContext at all.

根本没有必要设置DataContext。

However, the binding mode has to be set to OneWay, because the default is OneTime:

但是,绑定模式必须设置为OneWay,因为默认值为OneTime:

ItemsSource="{x:Bind ThisSentence, Mode=OneWay}"

In addition, the property has to notify about value changes. In a class derived from DependencyObject, this is usually done by making it a dependency property:

此外,酒店必须通知价值变化。在从DependencyObject派生的类中,通常通过使其成为依赖属性来完成:

public static readonly DependencyProperty ThisSentenceProperty =
    DependencyProperty.Register(
        "ThisSentence",
        typeof(MainPage),
        typeof(ObservableCollection<Book>),
        new PropertyMetadata(null));

public ObservableCollection<Book> ThisSentence
{
    get { return (ObservableCollection<Book>)GetValue(ThisSentenceProperty); }
    set { SetValue(ThisSentenceProperty, value); }
}

You should also await the Task in the Click handler.

您还应该等待Click处理程序中的Task。

private async void button_Click(object sender, RoutedEventArgs e)
{
    ThisSentence = await Task.Run(() => SentenceManager.GetSentence("0", "0"));
}

Note that event handlers are the exception to the rule that there shouldn't be any async void methods.

请注意,事件处理程序是规则的例外,不应该有任何异步void方法。


In case you want to use Binding instead of x:Bind, you should set the DataContext once in the Page's constructor, like

如果你想使用Binding而不是x:Bind,你应该在Page的构造函数中设置一次DataContext,就像

public MainPage()
{
    InitializeComponent();
    DataContext = this;
}

Now you could also write

现在你也可以写

ItemsSource="{Binding ThisSentence}"

#1


0  

First of all, when you bind to the ThisSentence property by x:Bind like

首先,当你通过x绑定到ThisSentence属性时:Bind like

ItemsSource="{x:Bind ThisSentence}"

it is not necessary to set the DataContext at all.

根本没有必要设置DataContext。

However, the binding mode has to be set to OneWay, because the default is OneTime:

但是,绑定模式必须设置为OneWay,因为默认值为OneTime:

ItemsSource="{x:Bind ThisSentence, Mode=OneWay}"

In addition, the property has to notify about value changes. In a class derived from DependencyObject, this is usually done by making it a dependency property:

此外,酒店必须通知价值变化。在从DependencyObject派生的类中,通常通过使其成为依赖属性来完成:

public static readonly DependencyProperty ThisSentenceProperty =
    DependencyProperty.Register(
        "ThisSentence",
        typeof(MainPage),
        typeof(ObservableCollection<Book>),
        new PropertyMetadata(null));

public ObservableCollection<Book> ThisSentence
{
    get { return (ObservableCollection<Book>)GetValue(ThisSentenceProperty); }
    set { SetValue(ThisSentenceProperty, value); }
}

You should also await the Task in the Click handler.

您还应该等待Click处理程序中的Task。

private async void button_Click(object sender, RoutedEventArgs e)
{
    ThisSentence = await Task.Run(() => SentenceManager.GetSentence("0", "0"));
}

Note that event handlers are the exception to the rule that there shouldn't be any async void methods.

请注意,事件处理程序是规则的例外,不应该有任何异步void方法。


In case you want to use Binding instead of x:Bind, you should set the DataContext once in the Page's constructor, like

如果你想使用Binding而不是x:Bind,你应该在Page的构造函数中设置一次DataContext,就像

public MainPage()
{
    InitializeComponent();
    DataContext = this;
}

Now you could also write

现在你也可以写

ItemsSource="{Binding ThisSentence}"