2

我有一个 wpf 窗口,我在其中通过 XMLDataProvider 使用 xml 数据。屏幕基于网格,所有数据都正确显示,已将 xml 定义如下...

<Grid.DataContext>
    <XmlDataProvider x:Name="Data" XPath="Book/Page" />
</Grid.DataContext>

在后面的代码中设置 xml 源代码如下...

InitializeComponent();

string appPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().CodeBase);
Data.Source = new Uri(appPath + @"\SNG.xml");

到目前为止一切都很好。但是现在我需要从后面代码中的 xml 文件中读取其中一个元素。我所有的搜索以及我发现的唯一方法是将其绑定到一个不可见的控件,然后从控件中读取数据。例如,从 xml 中读取 BookRef 我在 xaml 中有以下内容...

TextBlock Name="BookRefTextBox" Visibility="Hidden" Text="{Binding XPath=@BookRef}"/>

然后在后面的代码中......

string bookRef = BookRefTextBox.Text;

这行得通,然后我可以使用来自 xml 文件的数据......但它真的感觉像一个软糖。有没有更好的方法从代码隐藏部分中获取部分 xml 文件的值。

编辑:

忘了说我也试过把XmlDataProviderinWindows.Resources而不是 inGrid.DataContext作为我发现的一些例子。

但是,我找不到在后面的代码中设置 xml 文件路径的方法。添加到其中将其放入 Windows.Resource 不会更容易找到如何访问 Xml 文件中的数据。

EDIT2: 这是 XML 文件的示例。注意有多本书。

<Books>
  <Book Id="1" BookRef="12345" Name="My Book Name" Author="Author" Pages="2" >
    <Page PageId="1"/>
    <Page PageId="2"/>
  </Book>
  <Book Id="1" BookRef="67890" Name="My Second Book Name" Author="Author 2" Pages="1" >
    <Page PageId="1"/>
  </Book>
</Books>
4

2 回答 2

2

好的,这是另一种方式,虽然更复杂。

您是正确的,您需要将当前显示的页面与BookRefTextBox. 所以在 之上XmlDataProvider,我定义了一个CollectionViewSource,它可以用来跟踪当前显示的页面。

在下面的 XAML 代码中,BookRefTextBoxlistBox1(我使用 ListBox 来显示页面)都绑定到相同的CollectionViewSource,并且通过设置IsSynchronizedWithCurrentItem="True",当前项会在所选页面发生更改时更新。

有趣的是 BookRefTextBox.Test 的 XPath 表达式, XPath=../@BookRef意味着 BookRefTextBox 的文本是Find the parent element of the current page- which is Book, and display its BookRef attribute".

窗口的整个 XAML。

<Window x:Class="MyNamespace.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <XmlDataProvider x:Key="userDataXmlDataProvider1" Source="/Data/XMLFile1.xml" XPath="Books/Book/Page"/>
        <CollectionViewSource x:Key="userDataCollectionViewSource1" Source="{StaticResource userDataXmlDataProvider1}"/>
    </Window.Resources>
    <Grid DataContext="{StaticResource userDataXmlDataProvider1}">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="3*"/>
        </Grid.RowDefinitions>
        <TextBlock x:Name="BookRefTextBox" Grid.Row="0" Text="{Binding XPath=../@BookRef}" />
        <ListBox x:Name="listBox1" Grid.Row="1" 
                 IsSynchronizedWithCurrentItem="True"
                 ItemsSource="{Binding}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal" Margin="8,0,8,0">
                        <Label Content="{Binding XPath=@PageId}" Width="100" Margin="5" />
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

从后面的代码中,您可以获得 BookRefTextBox 的文本。

编辑:

为了从后面的代码中设置源代码:

如果XmlDataProvider在 中声明Window.Resources,它有一个x:Key属性,你通过 Key 而不是 Name 访问资源。

XmlDataProvider xdp = this.Resources["userDataXmlDataProvider1"]  as XmlDataProvider; 
xdp.Source = new Uri(...);
于 2014-12-24T04:32:45.987 回答
0

我相信我终于找到了避免使用隐藏控件的答案。首先非常感谢 kennyzx 的回答,虽然它仍然使用隐藏控件,但对于引导我得到这个答案是非常宝贵的。

不是将 XmlDataProvider 放在 Grid.Context 中,而是将它移到了 Window.Resources 中,并添加了一个 CollectionViewSource 来伴随它。

<Window.Resources>        
    <XmlDataProvider x:Name="books" x:Key="bookData" XPath="Books/Book/Page"/>
    <CollectionViewSource x:Key="collBookData" Source="{StaticResource bookData}"/>
</Window.Resources>

在后面的代码中定义了一个新的 XmlDataProvider,并且在窗口的构造函数中设置为对 XAML Windows.Resources 中定义的引用。

    XmlDataProvider bookData;

    public BookPage()
    {
        InitializeComponent();

        string appPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().CodeBase);
        bookData = (XmlDataProvider)this.Resources["bookData"];
        bookData.Source = new Uri(appPath + @"\SNG.xml");
    }

Grid 的 DataContext 设置为 CollectionViewSource。

    <Grid.DataContext>
        <Binding Source="{StaticResource collBookData}"/>
    </Grid.DataContext>

上述不是 100% 必要的,因为它可以在每个控件上指定,但这种方式可以更简单地绑定到表单上的每个控件。(此解决方案中没有隐藏控件,只有我想要实际显示的控件)。例如...

    <TextBlock Name="myTextBlockName" Style="{StaticResource MyTextBlockStyle}" Text="{Binding XPath=../@BookRef}" />

最后是在后面的代码中从 XML 中读取数据的位。

        XmlNode currentXmlNode = bookData.Document.SelectNodes("Books/Book/Page").Item(collBookData.View.CurrentPosition);
        string currentBookRef = currentXmlNode.ParentNode.Attributes["BookRef"].Value;

顺便说一句,此解决方案还允许我针对 collBookData.View 使用 MoveCurrentToPrevious 和 MoveCurrentToNext 来更改当前显示的页面(以前有一个隐藏的列表框控件来执行此操作,并且对该解决方案也不满意)。

于 2015-01-01T20:04:52.880 回答