>我有一个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>
好吧,这是另一种方式,不过更复杂。
您是正确的,您需要将当前显示的页面与BookRefTextBox
的文本同步。所以在XmlDataProvider
之上,我定义了一个CollectionViewSource
,可以用来跟踪当前显示的页面。
在下面的 XAML 代码中,BookRefTextBox
和listBox1
(我使用 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来更改正在显示的当前页面(以前有一个隐藏的列表框控件来做到这一点,并且对该解决方案也不满意)。