Setting style based on existence of an ancestor type Setting style based on existence of an ancestor type wpf wpf

Setting style based on existence of an ancestor type


I think @Xameli solution is what you are actually looking for...
but if you simply must do it in a style then you can achieve it using VisualTreeHelper like that:

<Style.Triggers>            <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}, Converter={StaticResource HasAncestorConverter}}" Value="True">                <Setter Property="Background"                        Value="{Binding Tag,RelativeSource={RelativeSource Self}}" />            </DataTrigger>        </Style.Triggers>

the converter:

class HasAncestorConverter : IValueConverter{    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)    {        //you probably will have to look a few levels up        var parent = VisualTreeHelper.GetParent(value) as ItemsControl;        return item != null;     }    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)    {        throw new NotImplementedException();    }}


According to @makc's response I solved the problem this way:

<Grid>    <Grid.Resources>        <local:HasAncestorConverter x:Key="HasAncestorConverter" />        <Style TargetType="TextBlock">                        <Style.Triggers>                <DataTrigger                    Binding="{Binding RelativeSource={RelativeSource                    AncestorType={x:Type ItemsControl}},                    Converter={StaticResource HasAncestorConverter}}" Value="True">                    <Setter Property="Background"                            Value="{Binding Tag,                            RelativeSource={RelativeSource                            AncestorType={x:Type ItemsControl}}}" />                </DataTrigger>            </Style.Triggers>        </Style>    </Grid.Resources>    <StackPanel>        <TextBlock Text="Out of ItemControl" />        <ItemsControl Tag="Blue" >            <TextBlock Text="Inside of ItemControl" />        </ItemsControl>    </StackPanel></Grid>  

Converter:

class HasAncestorConverter : IValueConverter{    public object Convert(object value, Type targetType, object parameter        , System.Globalization.CultureInfo culture)    {        object parent = null;        if (value != null && parameter != null &&            parameter is Type && value is DependencyObject)        {            var control = value as DependencyObject;            Type t = parameter as Type;            parent = ParentFinder.FindParent(control, t);        }        return parent != null;    }    public object ConvertBack(object value, Type targetType, object parameter        , System.Globalization.CultureInfo culture)    {        throw new NotImplementedException();    }}

Helper class for finding the parent of specific type:
Note: This helper find any kind of parent in logical or visual tree. for example in my case ItemsControl is a parent in the logical tree, and it can be a grandparent.

class ParentFinder{    public static object FindParent(DependencyObject child, Type parentType)    {        object parent = null;        var logicalParent = LogicalTreeHelper.GetParent(child);        var visualParent = VisualTreeHelper.GetParent(child);        if (!(logicalParent == null && visualParent == null))        {            if (logicalParent != null && logicalParent.GetType() == parentType)                parent = logicalParent;            else if (visualParent != null && visualParent.GetType() == parentType)                parent = visualParent;            else            {                if (visualParent != null)                    parent = FindParent(visualParent, parentType);                if (parent == null && logicalParent != null)                    parent = FindParent(logicalParent, parentType);            }        }        return parent;    }}


Use DataTemplate for the items in ItemsControl.

<ItemsControl ....    <ItemsControl.ItemTemplate>        <DataTemplate>            <TextBlock Text="{Binding }"                       Background="{Binding Tag,                                            RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>        </DataTemplate>    </ItemsControl.ItemTemplate>    <sys:String>Inside of ItemControl</String></ItemsControl>

Keep the style that you have if you need it for other setters, just remove the trigger.