【问题标题】:xmldataprovider using element values in code behindxmldataprovider 在后面的代码中使用元素值
【发布时间】:2015-01-02 04:10:12
【问题描述】:

我有一个 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 文件中的数据。

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>

【问题讨论】:

    标签: c# xml wpf code-behind xmldataprovider


    【解决方案1】:

    好吧,这里有另一种方法,不过更复杂。

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

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

    有趣的是BookRefTextBox.Test的XPath表达式,XPath=../@BookRef表示BookRefTextBox的Text是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 的文本。

    编辑:

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

    如果XmlDataProviderWindow.Resources 中声明,则它具有x:Key 属性,您可以通过键访问资源,而不是通过名称。

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

    【讨论】:

    • 谢谢,这看起来正是我想要的。但是我猜我将在这里阅读的“记录”不会与当前显示在屏幕上的记录同步,我的猜测是否正确?我的 XML 包含多个“书籍”和多个“页面”,我真的需要从当前屏幕上的那个阅读“BookRef”。
    • 哇,问题没那么简单,我还以为只有一个Book元素(也就是根元素)。
    • 在您的问题中显示您的 xml 示例,这会很有帮助。
    • 向问题添加了 xml 示例。我一直在尝试搜索是否有办法将 XDocument 链接到 XMLDataProvider 但没有提出任何建议。也许答案是按照我正在做的事情并从 xaml 中的隐藏文本块中读取信息,但是它确实看起来像一个软糖,我应该能够直接在代码隐藏中读取信息:(
    • 我已经更新了我的答案,为了获得当前显示的页面,您需要在 XAML 中进行。我在 XAML 中添加了一个文本块来显示当前显示页面的书的BookRef 属性。
    【解决方案2】:

    我相信我终于找到了避免使用隐藏控件的答案。首先非常感谢 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 来更改当前显示的页面(以前有一个隐藏的列表框控件来执行此操作,并且对该解决方案也不满意)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-28
      • 1970-01-01
      • 2012-11-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多