在 WPF 中,当 xml 文档在运行时发生更改时,如何刷新 xmlDataProvider?
我正在尝试在 Visual Studio WPF 中制作图像查看器/相册创建器。每个相册的图像路径存储在一个 xml 文档中,我绑定到该文档以在列表框中显示每个相册中的图像。 问题是当我在运行时添加图像或相册并将其写入 xml 文档时。我似乎无法更新 xml 文档的绑定,因此它们也会显示新的图像和相册。 在 XmlDataProvider 上调用 Refresh()
不会改变任何内容。 我不想重做 XmlDataProvider 的绑定,只需让它再次从同一源读取即可。
XAML:
...
<Grid.DataContext>
<XmlDataProvider x:Name="Images" Source="Data/images.xml" XPath="/albums/album[@name='no album']/image" />
</Grid.DataContext>
...
<Label Grid.Row="1" Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Bottom" Padding="0" Margin="0,0,0,5" Content="{x:Static resx:Resource.AddImageLabel}"/>
<TextBox Grid.Row="1" Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Name="newImagePath" Margin="0" />
<Button Grid.Row="1" Grid.Column="2" HorizontalAlignment="Left" VerticalAlignment="Bottom" Name="newImagePathButton" Content="{x:Static resx:Resource.BrowseImageButton}" Click="newImagePathButton_Click" />
...
<ListBox Grid.Column="0" Grid.ColumnSpan="4" Grid.Row="3" HorizontalAlignment="Stretch" Name="thumbnailList" VerticalAlignment="Bottom" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding BindingGroupName=Images}" SelectedIndex="0" Background="#FFE0E0E0" Height="110">
...
代码隐藏:
private void newImagePathButton_Click(object sender, RoutedEventArgs e)
{
string imagePath = newImagePath.Text;
albumCreator.addImage(imagePath, null);
//Reset import image elements to default
newImagePath.Text = "";
//Refresh thumbnail listbox
Images.Refresh();
Console.WriteLine("Image added!");
}
public void addImage(string source, XmlElement parent)
{
if (parent == null)
{
//Use default album
parent = (XmlElement)root.FirstChild;
}
//Create image element with source element within
XmlElement newImage = xmlDoc.CreateElement(null, "image", null);
XmlElement newSource = xmlDoc.CreateElement(null, "source", null);
newSource.InnerText = source;
newImage.AppendChild(newSource);
//Add image element to parent
parent.AppendChild(newImage);
xmlDoc.Save(xmlFile);
}
非常感谢您的帮助!
I am trying to make a image viewer/album creator in visual studio, wpf. The image paths for each album is stored in an xml document which i bind to to show the images from each album in a listbox.
The problem is when i add a image or an album at runtime and write it to the xml document. I can't seem to make the bindings to the xml document update so they show the new images and albums aswell.
Calling Refresh()
on the XmlDataProvider doesn't change anything.
I don't wish to redo the binding of the XmlDataProvider, just make it read from the same source again.
XAML:
...
<Grid.DataContext>
<XmlDataProvider x:Name="Images" Source="Data/images.xml" XPath="/albums/album[@name='no album']/image" />
</Grid.DataContext>
...
<Label Grid.Row="1" Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Bottom" Padding="0" Margin="0,0,0,5" Content="{x:Static resx:Resource.AddImageLabel}"/>
<TextBox Grid.Row="1" Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Name="newImagePath" Margin="0" />
<Button Grid.Row="1" Grid.Column="2" HorizontalAlignment="Left" VerticalAlignment="Bottom" Name="newImagePathButton" Content="{x:Static resx:Resource.BrowseImageButton}" Click="newImagePathButton_Click" />
...
<ListBox Grid.Column="0" Grid.ColumnSpan="4" Grid.Row="3" HorizontalAlignment="Stretch" Name="thumbnailList" VerticalAlignment="Bottom" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding BindingGroupName=Images}" SelectedIndex="0" Background="#FFE0E0E0" Height="110">
...
Code behind:
private void newImagePathButton_Click(object sender, RoutedEventArgs e)
{
string imagePath = newImagePath.Text;
albumCreator.addImage(imagePath, null);
//Reset import image elements to default
newImagePath.Text = "";
//Refresh thumbnail listbox
Images.Refresh();
Console.WriteLine("Image added!");
}
public void addImage(string source, XmlElement parent)
{
if (parent == null)
{
//Use default album
parent = (XmlElement)root.FirstChild;
}
//Create image element with source element within
XmlElement newImage = xmlDoc.CreateElement(null, "image", null);
XmlElement newSource = xmlDoc.CreateElement(null, "source", null);
newSource.InnerText = source;
newImage.AppendChild(newSource);
//Add image element to parent
parent.AppendChild(newImage);
xmlDoc.Save(xmlFile);
}
Thank you very much for any help!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
在这种情况下,我相信正确的方法是使用
ObservableCollection
并将其绑定到ListView
的ItemsSource
属性。因此,只需使用对象即可,无需使用 XML 文件。编辑:
整个概念是与
Refresh()
一起使用的。下一个示例是有效的。检查文档保存后是否调用了Refresh()
。...
The right way in this situation I beleive is to use
ObservableCollection
and bind it toItemsSource
property of yourListView
. So, just play with objects and no tricks with XML files.Edit:
Entire concept is work with
Refresh()
. Next sample is works. Check ifRefresh()
call is made after document saving....
可能的问题和解决方案#1
您是否也在 Application.Resources 块中声明了此 XmlDataProvider 资源?
如果这样做,XAML UI ListBox 元素“thumbnailList”将引用网格面板的 XmlDataProvider 实例。我猜测,由于我看不到 Window CS 文件构造函数中的代码,因此当您在 XmlDataProvider 中寻址 XmlDataProvider 时,您会引用 XmlDataProvider 的应用程序级实例,如
XmlDataProvider xmlDataProvider = Application.Current.FindResource("图像”)作为 XmlDataProvider;
XmlDocument xDoc = xmlDataProvider.Document;
如果是这种情况,请从 Grid 元素中删除 XmlDataProvider 资源。现在,当您的代码隐藏更新 XML 文件时,UI 将自动更新。
可能的问题和解决方案#2
我从您的 addImage() 方法中看到您引用了名为“xDoc”的实例变量。
另一种可能性是您在 Window 构造函数中创建一个 NEW XmlDocument,而不是引用 XAML 创建的 XmlDocument 对象。如果是这样,请获取当前 XmlDocument 的实例,而不是创建新实例。确保声明资源
在应用程序级别,并从网格元素 XmlDataProvider 中删除资源声明
XmlDataProvider xmlDataProvider = Application.Current.FindResource("Images") as XmlDataProvider;
或者在 Grid 元素处引用资源(您需要向 Grid 添加名称),并且不要在 Application.Resources 块中声明资源
XmlDataProvider xmlDataProvider = grid.FindResource("Images") as XmlDataProvider;
XmlDocument xDoc = xmlDataProvider.Document;
现在,当您的代码隐藏更新 XML 文件时,UI 将自动更新。
结论
如果您在代码隐藏
XmlDataProvider xmlDataProvider 中声明这两个类实例变量;
XmlDataProvider gridXmlDataProvider;
并将此代码放在您的 Window 构造函数中
xmlDataProvider = Application.Current.FindResource("Images") as XmlDataProvider;
gridXmlDataProvider = grid.FindResource("Images") as XmlDataProvider;
在添加节点并保存 XML 文档更改时,在 addImage 事件处理程序中停止。假设您最初从 xmlDataProvider 加载 oDoc,如上所示。在调试模式下运行并打开“监视”窗口并检查 xmlDataProvider 和 gridXmlDataProvider 的内容。打开每个文档的 Document 属性,并比较 InnerXml 属性的内容。在 xmlDataProvider(应用程序级别的资源)上,您会发现
反映了 XML 文件的最新节点更改。 gridXmlDataProvider(XAML UI 元素的资源)则不然。 InnerXml 属性显示没有变化。没有变化,不需要更新 UI。
仅供参考,我遇到了问题#1 - 在 Application.Resources 块和 Window.Resources 块中声明的相同 XmlDataProvider 资源。我从后一个声明开始,在通过 Application.Current.FindResource("name") 引用 XmlDataProvider 实例后遇到异常错误,将声明复制并粘贴到 Application.Resources 块中,留下在Window.Resources 块,造成两个引用问题。 XAML UI 使用 Window 数据上下文,而我的代码隐藏使用应用程序数据上下文更新了 XML 文件!每当我在 XML 文件中添加或删除节点时,UI (ListBox) 都不会更新!
BTW XmlDataProvider 已经实现了自己的通知机制,不需要使用 ObservableCollection。 oProv.Refresh() 不会导致绑定 UI 的刷新,因为它可能指向 XmlDataProvider(Grid 元素的)的不同实例,并且就该实例而言,没有发生任何更改。
这个答案对你来说可能来得太晚了,但我刚刚发现了这个东西,我想分享一下。
Possible Problem and Solution #1
Do you have this XmlDataProvider resource declared in the Application.Resources block as well?
If you do, the XAML UI ListBox element "thumbnailList" refers to the Grid panel's instance of the XmlDataProvider. I'm guessing, since I can't see the code in your Window CS file constructor, that you refer to the Application-level instance of the XmlDataProvider when you address the XmlDataProvider there as in
XmlDataProvider xmlDataProvider = Application.Current.FindResource("Images") as XmlDataProvider;
XmlDocument xDoc = xmlDataProvider.Document;
If this is the case, remove the XmlDataProvider resource from the Grid element. Now when your code-behind updates the XML file the UI will automatically update.
Possible Problem and Solution #2
I see from your addImage() method that you refer to an instance variable named "xDoc".
The other possibility is that you are creating a NEW XmlDocument in your Window constructor, instead of referencing the XAML created XmlDocument object. If so, get the instance of the current XmlDocument instead of creating a new instance. Make sure to declare the resource
at the Application level and remove the resource declaration from the Grid element
XmlDataProvider xmlDataProvider = Application.Current.FindResource("Images") as XmlDataProvider;
Or reference the resource at the Grid element (you will need to add a Name to the Grid) and do not declare the resource in the Application.Resources block
XmlDataProvider xmlDataProvider = grid.FindResource("Images") as XmlDataProvider;
XmlDocument xDoc = xmlDataProvider.Document;
Now when your code-behind updates the XML file the UI will automatically update.
Conclusions
If you declare these two class instance variables in your code-behind
XmlDataProvider xmlDataProvider;
XmlDataProvider gridXmlDataProvider;
and have this code in your Window constructor
xmlDataProvider = Application.Current.FindResource("Images") as XmlDataProvider;
gridXmlDataProvider = grid.FindResource("Images") as XmlDataProvider;
Put a stop in the addImage event handler right you add a Node and save the XML Document changes. Assuming you originally loaded oDoc from xmlDataProvider as shown above. Run in Debug Mode and open a Watch window and inspect the contents of xmlDataProvider and gridXmlDataProvider. Open the Document property on each, and compare the contents of the InnerXml property. On the xmlDataProvider (the Application-level's resource) you will find
the latest node changes to the XML file are reflected. Not so on the gridXmlDataProvider (the XAML UI element's resource). InnerXml property shows no changes. No changes, not need to update the UI.
FYI I had Problem #1 - the same XmlDataProvider resource declared in the Application.Resources block AND in the Window.Resources block. I started out with the latter declaration, ran into an exception error after I referred to the XmlDataProvider instance via Application.Current.FindResource("name"), copy and pasted the declaration into the Application.Resources block, LEAVING the resource declared in the Window.Resources block, creating a TWO REFERENCE problem. The XAML UI used the Window data context, while my code-behind updated the XML file with the Application data context! Whenever I added or removed nodes from the XML file the UI (ListBox) did not get updated!
BTW XmlDataProvider already implements its own notification mechanism, no need use an ObservableCollection. oProv.Refresh() does not cause the refresh of the bound UI because it may point to a different instance of the XmlDataProvider (the Grid element's), and as far as that instance is concerned, no changes have happened.
This answer probably comes too late for you, but I just found this stuff out, thought I share it.
在 XML 中
在计算机科学中
in xml
in cs
取自..http://www.infosysblogs.com/microsoft/2008/03 /wpf_updating_xmldataprovider_w.html
我在下面使用过;
和
在我的用户控件中;
Taken from..http://www.infosysblogs.com/microsoft/2008/03/wpf_updating_xmldataprovider_w.html
Ive used below;
and
and in my UserControl;