tkrag
tkrag

Reputation: 3

How do I use a window-level databound style in a DataTemplate

In a WPF project, my viewmodel has some general properties that I bind to a style. I then would like to use that style in a DataTemplate where I bind a collection from my viewmodel.

The databound style works outside the DataTemplate as expected, but does not apply inside. When debugging I can see that it is looking for the general properties inside the collection objects, so my question is, how do I inside a DataTemplate get a hold of properties from the viewmodel. I imagine I have to use a RelativeSource binding, but I have not been able to get it working.

This quick app should show what I am trying to do:

MainWindow.xaml

<Window x:Class="StyleTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:StyleTest"
        mc:Ignorable="d"
        Title="Test" 
        SizeToContent="WidthAndHeight">
    <Window.Resources>
        <Style TargetType="TextBlock" x:Key="Header">
            <Setter Property="FontSize" Value="{Binding FontSize}" />
            <Setter Property="Foreground" Value="{Binding Foreground}" />
        </Style>
        <DataTemplate x:Key="UserTemplate">
            <StackPanel>
                <TextBlock Style="{StaticResource Header}" Text="{Binding Name}" />
            </StackPanel>
        </DataTemplate>
    </Window.Resources>
    <Grid Margin="20">
        <StackPanel>
            <ItemsControl Name="Itemscontrol" ItemsSource="{Binding Users}" ItemTemplate="{StaticResource UserTemplate}" />
            <TextBlock Style="{StaticResource Header}">Style this.</TextBlock>
        </StackPanel>
    </Grid>
</Window>

MainWindow.cs

using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;

namespace StyleTest
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            Model m = new Model {
                FontSize = 28,
                Foreground = new SolidColorBrush(Colors.Orange),
                Users = new List<User>() };

            m.Users.Add(new User() { Name = "Mambo No. 1" });
            m.Users.Add(new User() { Name = "Right Hand Rob" });
            m.Users.Add(new User() { Name = "Perry Junior" });

            this.DataContext = m;
        }
    }

    public class Model
    {
        private int fontSize;
        public int FontSize { get => fontSize; set => fontSize = value; }

        private SolidColorBrush foreground;
        public SolidColorBrush Foreground { get => foreground; set => foreground = value; }

        private List<User> users;
        public List<User> Users { get => users; set => users = value; }
    }

    public class User
    {
        public string Name { get; set; }
    }
}

Upvotes: 0

Views: 36

Answers (1)

sTrenat
sTrenat

Reputation: 1049

I think you want something like this:

<Style TargetType="TextBlock" x:Key="Header">
    <Setter Property="FontSize" Value="{Binding  Path=DataContext.FontSize, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" />
    <Setter Property="Foreground" Value="{Binding Path=DataContext.Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" />
</Style>

Upvotes: 1

Related Questions