SonofNun
SonofNun

Reputation: 467

Get ItemsControl children to inherit foreground in WinRT

In a custom TemplatedControl I have an ItemsControl that is populated outside of the custom TemplatedControl. I want the (future) children of the ItemsControl to automatically inherit the Foreground value from the ItemsControl.

I want to be able to change the Foreground value from the TemplatedControl, and have the child controls update their Foreground as well.

Here's the ItemsControl I have:

<ItemsControl x:Name="PrimaryItems" ItemsSource="{TemplateBinding PrimaryItems}" Foreground="{TemplateBinding MyCustomForeground}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

And when I use the TemplatedControl, it'll look like this:

<Grid>
    <Controls:MyCustomControl MyCustomForeground="Blue">
        <Controls:MyCustomControl.PrimaryItems>
            <Button Content="Test button"/>
        </Controls:MyCustomControl.PrimaryItems>
    </Controls:MyCustomControl>
</Grid>

I want the Button foreground to automatically be Blue, since that's what I set as MyCustomForeground in my TemplatedControl.

Any tips?

Upvotes: 0

Views: 133

Answers (2)

pleasereset
pleasereset

Reputation: 240

I see, this one is tricky. If you try to use DependencyProperty heritage, this won't work (using the foreground property of your UserControl) :

<UserControl
    x:Class="TestApp1.CustomControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:TestApp1"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300"
    d:DesignWidth="400" Foreground="Blue">

    <StackPanel x:Name="PART_Container">
        <Button Content="Test"/>
        <TextBlock Text="Test"/>
    </StackPanel>
</UserControl>

If you try this snippet, the phone's template for the button will override Foreground="Blue" and thus it will have a white (or black depending on the theme) foreground. Note that Textblock is not styled, and won't display this behavior, it will successfully inherit the blue foreground from its parent UserControl.

How to walkaround this ? You seem to declare a custom dependency property MyCustomForeground, so you can implement a logic in the DependencyPropertyChanged handler. But you also have to apply your custom foreground each time your PrimaryItems changes.

Here's a working sample :

public sealed partial class CustomControl : UserControl
{
    public CustomControl()
    {
        this.InitializeComponent();
    }
    public Brush MyCustomForeground
    {
        get { return (Brush)GetValue(MyCustomForegroundProperty); }
        set { SetValue(MyCustomForegroundProperty, value); }
    }

    // Using a DependencyProperty as the backing store for MyCustomForeground.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty MyCustomForegroundProperty =
        DependencyProperty.Register("MyCustomForeground", typeof(Brush), typeof(CustomControl), new PropertyMetadata(null, OnCustomForegroundChanged));

    private static void OnCustomForegroundChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        CustomControl ctrl = (CustomControl)d;
        ctrl.ApplyCustomForeground();
    }

    public UIElement PrimaryItems
    {
        get { return (UIElement)GetValue(PrimaryItemsProperty); }
        set { SetValue(PrimaryItemsProperty, value); }
    }

    // Using a DependencyProperty as the backing store for PrimaryItems.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty PrimaryItemsProperty =
        DependencyProperty.Register("PrimaryItems", typeof(UIElement), typeof(CustomControl), new PropertyMetadata(null, OnPrimaryItemsChanged));

    private static void OnPrimaryItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        CustomControl ctrl = (CustomControl)d;
        // PART_Container is where I store my PrimaryItems
        ctrl.PART_Container.Children.Clear();
        ctrl.PART_Container.Children.Add((UIElement)e.NewValue);
        ctrl.ApplyCustomForeground();
    }

    private void ApplyCustomForeground()
    {
        // PART_Container is where I store my PrimaryItems
        foreach (var child in PART_Container.Children)
        {
            // Foreground is inherited by Control or TextBlock, or other classes... 
            // You would be better off using reflection here but that's off topic
            if (child is Control)
            {
                ((Control)child).Foreground = MyCustomForeground;
            }
            else if (child is TextBlock)
            {
                ((TextBlock)child).Foreground = MyCustomForeground;
            }
        }
    }
}

Upvotes: 0

pleasereset
pleasereset

Reputation: 240

Have you tried {TemplateBinding xxxx} ?

<Controls:MyCustomControl MyCustomForeground="{TemplateBinding Foreground}">
    <Controls:MyCustomControl.PrimaryItems>
        <Button Content="Test button"/>
    </Controls:MyCustomControl.PrimaryItems>
</Controls:MyCustomControl>

Upvotes: 1

Related Questions