0
votes

I have created a template for multiple listboxitems and some textblocks inside. In the settings the user can change the background of the app to black or white (and then the textblock foreground color should change the opposite accordingly). How can I bind the textblocks text to one property (of the itemlist (observablecollection)) and the foreground to another property (with a converter for the color) which is not in the same datacontext (but in the settings-datacontext)?

What I am trying to do:

<DataTemplate x:Key="ArticleItemTemplateClassic">
        <Grid>
            <!-- ... --->
             <TextBlock Text="{Binding Description}"
                        Foreground="{Binding SettingsFile.BlackBackgroundEnabled,
                        Converter={StaticResource InverseBackgroundColorConverter}}"/>
            <!-- The Context of the Foreground (SettingsFile.BlackBackgroundEnabled) -->
            <!-- should be not the same as where I bind Description -->
            </StackPanel>
            <!-- ... --->
        </Grid>
    </DataTemplate>

Thank you!

2

2 Answers

0
votes

You can explicitly specify a different DataContext for each item, if you are forced to do so. Although I am not sure why would you have two properties that align with the appearance of the same DataTemplate to be located in different containers.

0
votes

To do this, you will need to specify the Source of the Binding for the Foreground property. This can be done in many ways, but one example is to expose your Settings class as a resource.

For example:

<Grid x:Name="LayoutRoot">
    <Grid.Resources>
        <!-- If you want to use SettingsFile as a static, you might want to expose an accessor/wrapper class for it here instead. -->
        <settings:SettingsFile x:Name="SettingsFileResource" />
    </Grid.Resources>
    <ListBox ItemsSource="{Binding MyItems}">
        <ListBox.ItemTemplate>
            <DataTemplate x:Key="ArticleItemTemplateClassic">
                <Grid>
                    <!-- ... -->
                    <TextBlock Text="{Binding Description}"
                               <!-- Now change your Binding Path to the target property, and set the source to the resource defined above. -->
                    Foreground="{Binding BlackBackgroundEnabled, Source={StaticResource SettingsFileResource}, Converter={StaticResource InverseBackgroundColorConverter}}"/>

                    <StackPanel />
                    <!-- ... -->
                </Grid>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>

Alternativelty, it might be cleaner to use an AttachedProperty for this instead. EG:

public static bool GetBlackBackgroundEnabled(DependencyObject obj)
{
    return (bool)obj.GetValue(BlackBackgroundEnabledProperty);
}

public static void SetBlackBackgroundEnabled(DependencyObject obj, bool value)
{
    obj.SetValue(BlackBackgroundEnabledProperty, value);
}

// Using a DependencyProperty as the backing store for BlackBackgroundEnabled.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty BlackBackgroundEnabledProperty =
    DependencyProperty.RegisterAttached("BlackBackgroundEnabled", typeof(bool), typeof(Control), new PropertyMetadata(false, (s, e) =>
        {
            Control target = s as Control;
            SolidColorBrush brush = new SolidColorBrush();

            // Logic to determine the color goes here
            if (GetBlackBackgroundEnabled(target))
            {
                brush.Color = something;
            }
            else
            {
                brush.Color = somethingElse;
            }

            target.Foreground = brush;
        }));

Then you would use it like this:

<TextBlock settings:SettingsFile.BlackBackgroundEnabled="True" />