I've got a WPF application that reads an XML file and creates an XDocument
to bind to, passing its various elements down to other UI elements via DataContexts and such. The schema for the XML this application reads marks a few attributes on elements as entirely optional.
The method I'm using to bind is outlined in "How to: Bind to XDocument, XElement, or LINQ for XML Query Results". The application will load an XML file or create an empty XDocument, then assign it as the DataContext
for the UI's main grid...
XDocument newDoc = new XDocument(new XElement("mydoc"));
gridMain.DataContext = newDoc.Root;
Instances of an element with the document are then passed as the ItemsSource
for a ListBox
...
<ListBox ItemsSource="{Binding Elements[item]}">
<!-- ... -->
</ListBox>
And then, the DataTemplate
for the items in the ListBox have icons and a ToggleButton
whose states are defined by the value of a boolean relevant
attribute on each <item>
element. I wrote my own custom IValueConverter
classes to handle conversion between XML boolean strings, and System.Windows.Visibility
and bool
values...
<ListBox.ItemTemplate>
<DataTemplate>
<DockPanel LastChildFill="True">
<Grid Visibility="{Binding Attribute[relevant].Value, Converter={StaticResource BooleanToVisibilityConverter}}" Margin="2 0">
<StaticResource ResourceKey="RelevantIcon"/>
</Grid>
<Grid Visibility="{Binding Attribute[relevant].Value, Converter={StaticResource NegatedBooleanToVisibilityConverter}}" Margin="2 0">
<StaticResource ResourceKey="IrrelevantIcon"/>
</Grid>
<ToggleButton IsChecked="{Binding Attribute[relevant].Value, Converter={StaticResource BooleanConverter}}" VerticalAlignment="Center" Margin="2 0" Padding="5">Relevant</ToggleButton>
<TextBox Text="{Binding Value}" TextWrapping="Wrap" AcceptsReturn="True" AllowDrop="True" Margin="2 0"/>
</DockPanel>
</DataTemplate>
</ListBox.ItemTemplate>
Now, if I load a document in where every <item>
element has its relevant
attribute defined, this works as expected. But, the schema defines that relevant
may or may not be present. So, when I create an element or load in a document that's missing these attributes, the list item view completely breaks, silently. Both icons appear, and the toggle button seems to do absolutely nothing. Breakpoints reveal that my custom IValueConverter
s are never called for these elements, which indicates that the binding fails silently due to Attribute[relevant]
being null
, and null
has no properties, let alone Value
.
I've tried using FallbackValue
in the Binding
to no avail, and the null-conditional operator doesn't work in bindings - the XAML parser will exception at runtime.
The root of the problem seems to be that the bindings won't work if the attribute doesn't exist, and there doesn't seem to be a way to get it to have a default value or create the attribute if it doesn't exist. So, is there a way I can make the bindings behave the way I expect them to? If not, is there a way to add the attribute to each element if it's missing?