开发者

Hide DataTrigger if RelativeSource doesn't exist

I want to add a DataTrigger to my base TextBox style so that it sets the foreground color to a different value if it is in开发者_高级运维side of a DataGridCell that is selected. Here is what my trigger looks like:

<Style.Triggers>
    <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGridCell}}, Path=IsSelected}"
                 Value="True">
        <Setter Property="Foreground"
                Value="White" />
    </DataTrigger>
</Style.Triggers>

This works great, except that when my TextBox is not in a DataGrid the Binding fails and writes an exception to the output window. How can I prevent this.

I basically want to say if Parent is a DataGridCell then apply this trigger otherwise ignore it.


In general just only apply the style where applicable. If you want implicit application use nested styles:

<Style TargetType="{x:Type DataGrid}">
    <Style.Resources>
        <Style TargetType="{x:Type TextBox}">
            <Style.Triggers>
                <DataTrigger
                        Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGridCell}}, Path=IsSelected}"
                        Value="True">
                    <Setter Property="Foreground" Value="White" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Style.Resources>
</Style>

If you have other parts which you want to apply to all TextBoxes take out those parts in a serarate style and use BasedOn in the style which applies to the TextBoxes inside the DataGrid.


Edit: MultiDataTrigger seems to return right away if a condition is not met so you can avoid binding errors:

<Style TargetType="{x:Type TextBox}">
    <Style.Resources>
        <vc:HasAncestorOfTypeConverter x:Key="HasAncestorOfTypeConverter" AncestorType="{x:Type DataGridCell}" />
    </Style.Resources>
    <Style.Triggers>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition
                        Binding="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource HasAncestorOfTypeConverter}}"
                        Value="True" />
                <Condition
                        Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGridCell}}, Path=IsSelected}"
                        Value="True" />
            </MultiDataTrigger.Conditions>
            <Setter Property="Foreground" Value="Red" />
        </MultiDataTrigger>
    </Style.Triggers>
</Style>
public class HasAncestorOfTypeConverter : IValueConverter
{
    public Type AncestorType { get; set; }

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value == null) return false;
        DependencyObject current = value as DependencyObject;
        while (true)
        {
            current = VisualTreeHelper.GetParent(current);
            if (current == null)
            {
                return false;
            }
            if (current.GetType() == AncestorType)
            {
                return true;
            }
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}

This of course causes quite som overhead so it might not be such a good solution, then again if the RelativeSource-binding fails it also had to go up the tree first.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜