I got a problem binding an ItemTemplates Parent context inside an item template.
There are plenty of "workarounds" which only work in WPF (i.e. using FindAncestor
and AncestorType
). This are out of question, as it's not supported in Windows Store Apps.
Other solutions suggest using ElementName
. While this works in Windows Store Apps, it's not an acceptable solution, as it reusable DataTemplates impossible.
One solution I did read about was using Attached Properties/Attached Behaviors, which sounds like the way to go and is a very generic and reusable method. But I couldn't make it work so far.
My current attempt is, to create a global Attached Property and access it in the ItemTemplate
.
public class GlobalProperties : DependencyObject
{
public static object GetParentDataContext(DependencyObject obj)
{
return (object)obj.GetValue(ParentDataContextProperty);
}
public static void SetParentDataContext(DependencyObject obj, object value)
{
obj.SetValue(ParentDataContextProperty, value);
}
// Using a DependencyProperty as the backing store for ParentDataContext. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ParentDataContextProperty =
DependencyProperty.RegisterAttached("ParentDataContext",
typeof(object),
typeof(GlobalProperties),
new PropertyMetadata(null, ParentDataContextChanged));
private static void ParentDataContextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
SetParentDataContext(d, e.NewValue);
}
}
And my XAML (simplified by inlining the DataTemplate within the ListViews XAML Code. It will be later stored outside in an DataTemplate.xaml file.
<ListView
my:GlobalProperties.ParentDataContext="{Binding}"
ItemsSource="{Binding Questions}"
>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
<Setter Property="Margin" Value="0,-1,0,0" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid Background="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(my:GlobalProperties.ParentDataContext).Site.Styling.TagBackgroundColor}">
<!-- Item Related DataBindings -->
</Grid>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Where my
is the namespace where my GlobalProperties
is defined.
When I have a breakpoint in ParentDataContextChanged
it's definitely called with the DataContext. But I can't get the XAML code to work to read it. The Background
Xaml Property is always empty and the background always remains white (color saved in the TagBackgroundColor
property is red).
Anyone know what's wrong with the code/attempt?
update
Also Background="{Binding RelativeSource={RelativeSource Self}, Path=(my:GlobalProperties.ParentDataContext).Site.Styling.TagBackgroundColor}"
doesn't work, since that's what there in most website that show attached properties for such a case.
update 2 Example of of the ViewModel for better clarification
public class QuestionsViewModel : ViewModel
{
// Site.Styling.BackgroundColor to be bound to certain ItemTemplate
// Properties, but don't have access to it from the ItemTemplate
// because it has the context of one item from Questions
public Site Site { get; set; };
// Questions bound to ListView.DataSource > becomes Item's DataContext
public IEnumerable<Question> Questions { get; set; };
}
public class Site
{
public Style Styling { get; set; }
}
public class Style
{
public string ForegroundColor { get; set; }
public string BackgroundColor { get; set; }
public string LinkColor { get; set; }
}