XmlDataProvider error in XAML
Hi.
I'm trying to bind to some XML in an XmlDataProvider, defined declaratively in the XML thus:
<XmlDataProvider x:Key="ImageData">
<data xmlns="" >
<text>TEXT</text>
</data>
</XmlDataProvider>
Cider's giving me an warning, saying the XML elements within the data provider are invalid child elements, and if I switch to design view I get an 'Error reading the designerfile' message. If I take out the <data>...</data> XML, leaving the data provider, it's fine.
The XAML above has been tried in Window.Resources and Grid.Resources.
I'm stuck.Any ideas?
It looks like a designer bug. I get the same problem when I try to open the XmlDataProvider sample in the SDK (which runs fine) in the designer.
Window1.xaml from the XmlDataSource sample in the SDK:
<StackPanel
xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"
Background="Cornsilk"
>
<StackPanel.Resources>
<XmlDataProvider x:Key="BookData" XPath="/Books">
<Books xmlns="">
<Book ISBN="0-7356-0562-9" Stock="in">
<Title>XML in Action</Title>
<Summary>XML Web Technology</Summary>
</Book>
<Book ISBN="0-7356-1370-2" Stock="in">
<Title>Programming Microsoft Windows With C#</Title>
<Summary>C# Programming using the .NET Framework</Summary>
</Book>
<Book ISBN="0-7356-1288-9" Stock="out">
<Title>Inside C#</Title>
<Summary>C# Language Programming</Summary>
</Book>
<Book ISBN="0-7356-1377-X" Stock="in">
<Title>Introducing Microsoft .NET</Title>
<Summary>Overview of .NET Technology</Summary>
</Book>
<Book ISBN="0-7356-1448-2" Stock="out">
<Title>Microsoft C# Language Specifications</Title>
<Summary>The C# language definition</Summary>
</Book>
</Books>
</XmlDataProvider>
<DataTemplate x:Key="BookDataTemplate">
<TextBlock FontSize="12" Foreground="Red">
<TextBlock.Text>
<Binding XPath="Title"/>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</StackPanel.Resources>
<TextBlock FontSize="18" FontWeight="Bold" Margin="10"
HorizontalAlignment="Center">XML Data Source Sample</TextBlock>
<ListBox
Width="400" Height="300" Background="Honeydew"
ItemsSource="{Binding Source={StaticResource BookData}, XPath=Book}"
ItemTemplate="{StaticResource BookDataTemplate}"/>
</StackPanel>
It looks like the parser doesnt fully support this scenario quite yet (the December CTP is a very early release).
There are three things preventing the designer from opening:
- the inline XML data island
- the ItemsSource
- the ItemTemplate
If you push the XML data island to a separate file by specifying the Source property, that fixes the first problem. The second and third problems can be addressed by wiring up the ListBox binding from code.
<!-- Window1.xaml -->
<Window x:Class="WindowsApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"
Title="WindowsApplication1"
Loaded="OnWindowLoaded"
>
<StackPanel
Background="Cornsilk"
Name="stackPanel1"
>
<StackPanel.Resources>
<XmlDataProvider Source="Books.xml" x:Key="BookData" XPath="/Books">
</XmlDataProvider>
<DataTemplate x:Key="BookDataTemplate">
<TextBlock FontSize="12" Foreground="Red" Text="{Binding XPath=Title}"/>
</DataTemplate>
</StackPanel.Resources>
<TextBlock FontSize="18" FontWeight="Bold" Margin="10"
HorizontalAlignment="Center">XML Data Source Sample</TextBlock>
<ListBox Name="listBox1"
Width="400" Height="300" Background="Honeydew"/>
</StackPanel>
</Window>
// Window1.xaml.cs
private void OnWindowLoaded(object sender, EventArgs e)
{
// Find the "StaticResource" called BookData
Binding binding = new Binding();
binding.Source = stackPanel1.FindResource("BookData");
binding.XPath = "Book";
// same as
// ItemsSource="{Binding Source={StaticResource BookData}, XPath=Book}
listBox1.SetBinding(ListBox.ItemsSourceProperty, binding);
// same as
// ItemTemplate="{StaticResource BookDataTemplate}"
listBox1.ItemTemplate = stackPanel1.FindResource("BookDataTemplate") as DataTemplate;
}
<!-- Books.xml -->
<Books xmlns="">
<Book ISBN="0-7356-0562-9" Stock="in">
<Title>XML in Action</Title>
<Summary>XML Web Technology</Summary>
</Book>
<Book ISBN="0-7356-1370-2" Stock="in">
<Title>Programming Microsoft Windows With C#</Title>
<Summary>C# Programming using the .NET Framework</Summary>
</Book>
<Book ISBN="0-7356-1288-9" Stock="out">
<Title>Inside C#</Title>
<Summary>C# Language Programming</Summary>
</Book>
<Book ISBN="0-7356-1377-X" Stock="in">
<Title>Introducing Microsoft .NET</Title>
<Summary>Overview of .NET Technology</Summary>
</Book>
<Book ISBN="0-7356-1448-2" Stock="out">
<Title>Microsoft C# Language Specifications</Title>
<Summary>The C# language definition</Summary>
</Book>
</Books>
Hope that this helps - I've filed a bug for us to work on this scenario. Thanks for trying out the December CTP!
Jessica
Thanks for your help.
I've gone a different path - creating the XmlDataProvider in code and calling SetContext on the control from the 'code behind'. I can set the XML programatically which is more useful in my demo, and seems to work well.
Regards,
F
Hello!
I have a related problem. I'm not sure this is the right forum but I'll give it a try. I am using Expressive Interactive Designer January 2006 Community Technology Preview.My problem is that I want to generate TextBlocks from the content of an xml-file. The databind in itself is no problem, I can get the data from the xml-file to a manually created TextBlock, but not to a TextBlock that I generate in the C#-code.
If I create the TextBlocks manually I can create the databind with this code.
Binding binding = new Binding();
binding.Source = Grid.FindResource("tvDS");
binding.XPath = "/tv/programme[1]/title";
TextBlock1.SetBinding(TextBlock.TextProperty, binding);
This gets the title of the first tv-program and displays it in TextBlock1, just as expected.When I loop over the list generated from the xml-file I can create the TextBlocks that I need, but the databind does not work. This code:
for (i = 0; i < ListBox.Items.Count; i++)
{
Binding binding = new Binding();
binding.Source = Grid.FindResource("tvDS");
binding.XPath = "/tv/programme[" + i + "]/title)";
TextBlock temp = new TextBlock(); temp.SetBinding(TextBlock.TextProperty, binding);
StackPanel1.Children.Add(temp);
}
...creates the TextBlocks, but for some reason the databind does not work, the TextBlocks are empty.Any ideas? I would be very grateful for some help...
Thanks,
Tomas Hansson
Hi Tomas
This isn't quite answering your question, but do you really have to generate the textblocks in code?
If you want a list of TV titles, you can do it with a listbox and a data template, thus:
XAML:
<Grid>
<ListBox Background="AliceBlue" Name="tvlist" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding XPath=title}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
Code:
public Window1()
{
InitializeComponent();
}
public override void EndInit()
{
base.EndInit();
XmlDataProvider dp = new XmlDataProvider();
XmlDocument doc = new XmlDocument();
doc.LoadXml(@"<tv><programme><title>Title1</title></programme><programme><title>Title2</title></programme></tv>");
dp.Document = doc;
dp.XPath = "tv/programme";
tvlist.DataContext = dp;
}
The data template on the list box 'tvlist' creates TextBlocks for you. Does this help?
I'm not sure this the *the* most efficient way of doing it, but it works.
Regards,
Francis
Hi Fran,
Thanks for your answer, but it is unfortunately not solving my problem. Generating a ListBox with all the programmes is not what I want to do.
I want to be able to redesign and move the textBlocks, not only have them in a fixed ListBox. I want to display them in a horizontally scrollable row, therefore I need to generate a separate TextBlock for each program.
Or at least so I think. Or is it somehow possible to change the properties of the ListBox and the TextBlocks in it so that they are displayed horizontally, with some spacing between, with borders etc... I have tried to do that as well, but without success. Anyone knows how to do this?
A side issue: How do I uncomment code in the XAML-file?
Grateful for all help I can get.
/Tomas
Hi Tomas.
I believe you can do what you want with a listbox. You can change how the listbox displays its items by changing the ItemsPanel property of the listbox.
I'm not an expert, but I believe this will allow you to change how the items are shown, including making them horizontal.
For examples, try looking at some of the presentations from PDC05:
http://microsoft.sitestream.com/PDC05/
There are some really 'funky' listboxes towards the start of Kevin Moore's presentation PRS431. To find it, select 'presentation' and scroll down the list that appears.
There may be more in the other presentations - I haven't the time to watch them all.
Sorry I can't be more helpful.
F
OK, maybe I can be slightly more helpful!
It turns out horizontal listboxes are relatively easy.
Change the XAML to this:
<Grid>
<ListBox Background="AliceBlue" Name="tvlist" ItemsSource="{Binding}" Height="50">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Margin="3,3,3,3" Text="{Binding XPath=title}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
and the listbox is horizontal. Now you need to play about with the contents of the data template to display each item how you want it. At the moment, it only has a textblock in it, but I guess there's no reason why you couldn't add more functionality in here - a stackpanel, a grid, whatever.
HTH,
F
Great! That was exactly what I needed, makes it all so much easier.
Thanks! 
Tomas
And then comes the given follow-up question. How do I change the look of only the selected item in the list?
EDIT: Found it. Solved it by using DataTriggers to update the graphic of the selected row in the list.
/Tomas