Flowdocument and Databinding - wpf

After thoroughly reading the documentation on flowdocuments (in WPF) it seems as though flowdocument does not easily support databinding. PLEASE say this is not true! I have a listbox using the sample data in Expression Blend and I inserted a textblock into the flowdocument. The textblock (text property) is databinded to the string data in the listbox. After running the project I would expect that the textblock text changes as the listbox selection changes, but nothing happens. Databinding is not working. What is the easiest way to make databinding work with flowdocument?
Here is the XAML.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="WpfApplication1.MainWindow"
x:Name="Window"
Title="MainWindow"
Width="640" Height="480">
<Window.Resources>
<DataTemplate x:Key="ItemTemplate">
<StackPanel>
<TextBlock Text="{Binding Property1}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource SampleDataSource}}">
<FlowDocumentScrollViewer Margin="120,64,256,126">
<FlowDocument>
<Paragraph><Run Text="Only A Test"/><InlineUIContainer>
<TextBlock TextWrapping="Wrap" Text="{Binding Collection[0].Property1}" Height="56" Width="112"/>
</InlineUIContainer></Paragraph>
</FlowDocument>
</FlowDocumentScrollViewer>
<ListBox ItemTemplate="{DynamicResource ItemTemplate}" ItemsSource="{Binding Collection}" Margin="0,83.847,52,62.153" HorizontalAlignment="Right" Width="200"/>
</Grid>
</Window>

According to this Microsoft documentation in April 2009, this is not possible:
While there are many great features in flow documents, if your documents are generated from dynamic data, you have a bit of a problem: there is no support for data binding in flow documents. The flow document elements (Section, Table, Run, Paragraph and the like) are dependency objects, but don't define any dependency properties that would allow you to dynamically change or generate content.

Related

implicit DataTemplates vs. sample data vs. blendability

I have two simple ViewModels, NodeViewModel and LeafViewModel that can be items in a TreeView. Just like below. Templates are applied implictly because I don't want a custom template selector.
<UserControl x:Class="MyProject.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:ViewModels="clr-namespace:MyProject.ViewModels" mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" d:DataContext="{d:DesignData /SampleData/NodeViewModelSampleData.xaml}">
<UserControl.Resources>
<HierarchicalDataTemplate DataType="{x:Type ViewModels:NodeViewModel}" ItemsSource={Binding Children}>
<StackPanel Orientation="Horizontal">
<CheckBox Content="{Binding Name}" IsChecked="{Binding Result}"/>
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type ViewModels:LeafViewModel}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" />
</StackPanel>
</HierarchicalDataTemplate>
</UserControl.Resources>
<TreeView ItemsSource="{Binding Children}" />
</UserControl>
How can I generate sample data in blend that contains a tree with both NodeViewModels and LeafViewModels and then display it as the data in the treeview while still using implict template selection?
In the absence of using some kind of mocking framework, I've found that the easiest way to do this is to just hack together a class that generates instances of my view models and use it as a data source in Blend.
It occurs to me that it might be even easier to just define the test data in XAML, though this is contingent on the view model classes being designed to allow that (e.g. with parameterless constructors and a ContentProperty attribute, among other things).
I think the answer is simple: You can't.
Blend doesn't really work well with implicit datatemplates and template selectors. This is not only true for sample data but also inplace wysiwyg template editing. So for blendability you should try to avoid implict templates and template selectors whenever you can.

Problem with static data binding in wpf

I'm relatively new to wpf and I quite don't understand binding yet.
I want to have several combo boxes in my application with the same items. The basic solution would be to copy paste but that just isn't good practice. So I thought to put a static resource with the content I want and bind all combo boxes to it. It compiles and runs well but the combo box is empty.
Here's the code:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ItemsControl x:Key="Validations">
<ItemsControl.Items>
<ComboBoxItem>String</ComboBoxItem>
<ComboBoxItem>Numeric</ComboBoxItem>
</ItemsControl.Items>
</ItemsControl>
and here's the combo box:
<ComboBox ItemsSource="{Binding Source={StaticResource Validations}}"/>
I know the solution for this is probably simple but I haven't figured it out yet. I'll keep trying ;)
Thanks
Make the resource a list of strings, not a visual element, then use the StaticResource extension to assign it to the ItemsSource property, like so:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<x:ArrayExtension x:Key="Data" Type="{x:Type sys:String}">
<sys:String>String1</sys:String>
<sys:String>String2</sys:String>
<sys:String>String3</sys:String>
</x:ArrayExtension>
</Window.Resources>
<Grid>
<StackPanel>
<ComboBox ItemsSource="{StaticResource Data}"/>
<ComboBox ItemsSource="{StaticResource Data}"/>
<ComboBox ItemsSource="{StaticResource Data}"/>
</StackPanel>
</Grid>
</Window>
Note the definition of the xmlns:sys namespace (maps to namespace System in assembly mscorlib) and the use of the x:ArrayExtension element to declare a simply array in XAML.

Converter problem with XmlDataProvider

Sorry for this, I've just started programming with wpf. I can't seem to figure out why the following xaml displays "System.Xml.XmlElement" instead of the actual xml node content. This is displayed 5 times in the listbox whenever I run it. Not sure where I'm going wrong...
<Window x:Class="TestBinding.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<XmlDataProvider x:Key="myXmlSource" XPath="/root">
<x:XData>
<root xmlns="">
<name>Steve</name>
<name>Arthur</name>
<name>Sidney</name>
<name>Billy</name>
<name>Steven</name>
</root>
</x:XData>
</XmlDataProvider>
<DataTemplate x:Key="shmooga">
<TextBlock Text="{Binding}"/>
</DataTemplate>
</Window.Resources>
<Grid>
<ListBox ItemTemplate="{StaticResource shmooga}"
ItemsSource="{Binding Source={StaticResource myXmlSource}, XPath=name}">
</ListBox>
</Grid>
</Window>
Any help would be very much appreciated. Thanks!
Your ItemsSource Binding is returning the collection of 'name' elements. These are of type XmlElement. This is done because it allows bindings to get at other properties of the XmlElement, but means that if you textually display the result of the binding then you get System.Xml.XmlElement rather than the textual content.
To get the textual content, add an additional XPath to your ItemTemplate binding to specify that the TextBlock.Text property should bind specifically to the text of the element, not the element object itself:
<DataTemplate x:Key="shmooga">
<TextBlock Text="{Binding XPath=text()}"/> <!-- Note XPath on Binding -->
</DataTemplate>

WPF - Databind to a StackPanel using DataTemplates

I've modified my question since it has changed focus when trying things out.
I narrowed the problem down to the following...
I try to bind the selected Item of a TreeView to a StackPanel (or some other container that can hold User Controls). This container will then display a UserControl, depending on the type of the selected item.
Here is the xaml of the StackPanel (both treeview and stackpanel are in the same window ==> different grid column)
<StackPanel Grid.Column="2" MinWidth="500" DataContext="{Binding ElementName=myTree, Path=SelectedItem, Mode=OneWay}">
<StackPanel.Resources>
<DataTemplate DataType="{x:Type mvTypes:MyTypeA}">
<controls:UserControlA DataContext="{Binding}" />
</DataTemplate>
<DataTemplate DataType="{x:Type mvTypes:MyTypeB}">
<controls:UserControlB DataContext="{Binding}" />
</DataTemplate>
</StackPanel.Resources>
</StackPanel>
When I place a user control directly under the stackpanel (not in the resources), it displays it with the selected object as their datacontext.
Idem if I place a TextBox in it, it will show the correct type of the selected item.
<TextBox Name="textBox1" Text="{Binding}" />
For some reason, placing it within a DataTemplate (even without setting the DataType) results in nothing to display.
Any sugestions. I'm thinking that maybe a StackPanel is not the right control for this, though I can't seem to find other controls that look suitable as containers like this.
Thanks in advance.
Replace the StackPanel in your example with ContentPresenter and instead of DataContext set the Content property. That should work.
Although you have set the Binding on the second custom control, are you setting the DataContext, as the binding is the route to the information and the DataContext is the information it applies this binding information to.
Andrew
You can create a UserControl to display the TreeView and the selection info on the right, all in one. It saves you from creating any custom control. A custom control is basically unnecessary since you do not create anything which didn't exist before.
<UserControl x:Class="NameSpace.SelectionView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="namespace.Controls"
Height="300" Width="300">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TreeView Name="customTree">
<!--Items go here-->
</TreeView>
<StackPanel Grid.Column="1" MinWidth="50" DataContext="{Binding ElementName=customTree, Path=SelectedItem, Mode=OneWay}">
<StackPanel.Resources>
<DataTemplate DataType="{x:Type StylingTest:CustomViewModelA}">
<controls:CustomADetailsControl />
</DataTemplate>
<DataTemplate DataType="{x:Type StylingTest:CustomViewModelB}">
<controls:CustomBDetailsControl />
</DataTemplate>
</StackPanel.Resources>
<TextBlock Text="{Binding}"/>
</StackPanel>
</Grid>
</UserControl>
Any other custom behaviour, I'm sure you could create or set in styles/templates here.
Also, you might find one of my other answers useful.
Good luck with wpf, cheers.

Binding to a data template control property

Is it possible to bind something to a property of a control in a data template entirely in XAML? The following code is a simplified version of the problem I'm running into. I'd like the text of the TextBlock (displayName) to be updated as the user types in the TextBox located in the DataTemplate.
<Window x:Class="WpfApplication4.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:WpfApplication4="clr-namespace:WpfApplication4"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<DataTemplate DataType="{x:Type WpfApplication4:Foo}">
<TextBox Text="{Binding Path=Name}" />
</DataTemplate>
<WpfApplication4:Foo x:Key="testObject" Name="This is a test" />
</Window.Resources>
<StackPanel>
<TextBlock x:Name="displayName" Margin="5" />
<ContentControl x:Name="contentControl" Margin="5" Content="{StaticResource testObject}" />
</StackPanel>
No, at least, not from XAML. You could write code to traverse the visual tree and find the element you want to bind to, but that would be nasty.
But in your particular example, would it not make sense to just bind the TextBlock to the same data object (Foo instance)?

Resources