我正在尝试在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);
}
非常感谢您的帮助!
答案 0 :(得分:4)
我相信这种情况的正确方法是使用ObservableCollection
并将其绑定到ItemsSource
的{{1}}属性。所以,只需使用对象,不要使用XML文件。
修改强>
整个概念适用于ListView
。下一个样本是有效的。检查文档保存后是否进行了Refresh()
调用。
Refresh()
...
<ListView x:Name="uiList" ItemsSource="{Binding}">
<ListView.DataContext>
<XmlDataProvider x:Name="DataSource" Source="c:\XMLFile.xml" XPath="/root/item" />
</ListView.DataContext>
<ListView.ItemTemplate>
<DataTemplate>
<Border Width="40" Height="40" Background="Gray">
<Label Content="{Binding Attributes[0]}" />
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
答案 1 :(得分:1)
您是否也在Application.Resources块中声明了此XmlDataProvider资源?
如果这样做,XAML UI ListBox元素“thumbnailList”指的是Grid面板的XmlDataProvider实例。我猜测,因为我看不到你的Window CS文件构造函数中的代码,当你在
中解决XmlDataProvider时,你引用了XmlDataProvider的应用程序级实例XmlDataProvider xmlDataProvider = Application.Current.FindResource(“Images”)as XmlDataProvider;
XmlDocument xDoc = xmlDataProvider.Document;
如果是这种情况,请从Grid元素中删除XmlDataProvider资源。现在,当您的代码隐藏更新XML文件时,UI将自动更新。
我从你的addImage()方法看到你引用了一个名为“xDoc”的实例变量。
另一种可能性是您在Window构造函数中创建一个新的XmlDocument,而不是引用XAML创建的XmlDocument对象。如果是这样,请获取当前XmlDocument的实例,而不是创建新实例。确保声明资源 在应用程序级别并从Grid元素中删除资源声明
XmlDataProvider xmlDataProvider = Application.Current.FindResource(“Images”)as XmlDataProvider;
或者在Grid元素中引用资源(您需要向Grid添加一个Name)并且不在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;
在addImage事件处理程序中设置一个停止,然后添加一个Node并保存XML Document更改。假设您最初从xmlDataProvider加载oDoc,如上所示。在调试模式下运行并打开Watch窗口并检查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数据上下文,而我的代码隐藏使用Application数据上下文更新了XML文件!每当我从XML文件中添加或删除节点时,UI(ListBox)都没有得到更新!
BTW XmlDataProvider已经实现了自己的通知机制,不需要使用ObservableCollection。 oProv.Refresh()不会导致绑定UI的刷新,因为它可能指向XmlDataProvider的不同实例(Grid元素),并且就该实例而言,没有发生任何更改。
这个答案对你来说可能来得太晚了,但我只是发现了这些东西,以为我分享了它。
答案 2 :(得分:0)
<XmlDataProvider Source="XMLFile1.xml" XPath="Data" DataChanged="XmlDataProvider_DataChanged"></XmlDataProvider>
</Window.DataContext>
in cs
private void XmlDataProvider_DataChanged(object sender, EventArgs e)
{
Dispatcher.BeginInvoke((Action)(() =>
{
XmlDataProvider oProv = this.DataContext as XmlDataProvider;
oProv.Refresh();
}));
}
答案 3 :(得分:0)
取自.. http://www.infosysblogs.com/microsoft/2008/03/wpf_updating_xmldataprovider_w.html
我在下面使用过;
select PERSONALID, MIN(LOGDATE) as mindate
from TABLE
group by PERSONALID
order by mindate
和
XmlDataProvider xdp = this.Resources["userDataXmlDataProvider1"] as XmlDataProvider;
xdp.Source = new Uri(MyPath + @"\Projects.xml");
FileSystemWatcher watcher = new FileSystemWatcher();
//set the path of the XML file appropriately as per your requirements
watcher.Path = MyPath;
//name of the file i am watching
watcher.Filter = "Projects.xml";
//watch for file changed events so that we can refresh the data provider
watcher.Changed += new FileSystemEventHandler(file_Changed);
//finally, don't forget to enable watching, else the events won't fire
watcher.EnableRaisingEvents = true;
和我的UserControl;
void file_Changed(object sender, FileSystemEventArgs e)
{
XmlDataProvider xdp = this.Resources["userDataXmlDataProvider1"] as XmlDataProvider;
xdp.Refresh();
}