在代码隐藏中使用元素值的 XMLdataProvider

本文关键字:元素 XMLdataProvider 代码 隐藏 | 更新日期: 2023-09-27 18:35:19

>我有一个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 文件部分的值。

编辑:

忘了说我也尝试过将XmlDataProvider放在Windows.Resources中,而不是像我发现的一些例子那样放在Grid.DataContext中。

但是,我找不到在代码隐藏中设置xml文件路径的方法。除此之外,将其放在Windows.Resource中并不能使查找如何从XML文件访问数据变得更加容易。

编辑2:下面是 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>

在代码隐藏中使用元素值的 XMLdataProvider

好吧,这是另一种方式,不过更复杂。

您是正确的,您需要将当前显示的页面与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 的文本。

编辑:

为了从代码隐藏设置源代码:

如果在 Window.Resources 中声明XmlDataProvider,则它具有 x:Key 属性,您可以通过 Key 而不是 Name 访问资源。

XmlDataProvider xdp = this.Resources["userDataXmlDataProvider1"]  as XmlDataProvider; 
xdp.Source = new Uri(...);
我相信

我终于找到了避免使用隐藏控件的答案。首先非常感谢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");
    }

网格的 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;
顺便说一句

,这个解决方案还允许我使用MoveCurrentToLast和MoveCurrentToNext来对抗collBookData.View来更改正在显示的当前页面(以前有一个隐藏的列表框控件来做到这一点,并且对该解决方案也不满意)。