基于祖先类型的存在设置样式 [英] Setting style based on existence of an ancestor type
问题描述
我有 2 套 TextBlocks
,其中一些在 ItemControl
中,有些不在.
I have 2 sets of TextBlocks
some of them are in an ItemControl
and some of them are not.
如果 TextBlock
的祖先是 ItemControl
,我想创建一个样式(仅基于类型)设置背景.
I want to make a style (just based on type) which sets the background of the TextBlock
if its ancestor is an ItemControl
.
我可以使用以下代码来完成,但我的问题是在日志(和输出窗口)上显示了数据投标错误消息,因为 TextBlocks
没有 ItemControl
作为他们的祖先.
I can do it using the following code but my problem is that on the log (and output window) a data biding error message is displayed because of the TextBlocks
which do not have ItemControl
as their ancestor.
是否有更好的方法来完成此任务并避免出现此错误消息?
Is there a better way to do this task and avoid this error message?
<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>
转换器:
class HasAncestorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
return value != null;
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
错误信息:
System.Windows.Data 错误:4:无法找到引用RelativeSource FindAncestor, AncestorType='System.Windows.Controls.ItemsControl', AncestorLevel='1''的绑定源.绑定表达式:路径=;数据项=空;目标元素是 'TextBlock' (Name='');目标属性是NoTarget"(类型Object")
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.ItemsControl', AncestorLevel='1''. BindingExpression:Path=; DataItem=null; target element is 'TextBlock' (Name=''); target property is 'NoTarget' (type 'Object')
推荐答案
根据@makc的回复我是这样解决的:
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>
转换器:
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类:
注意:此助手可在逻辑或可视树中查找任何类型的父项.例如在我的例子中 ItemsControl
是逻辑树中的父级,它可以是祖父级.
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;
}
}
这篇关于基于祖先类型的存在设置样式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!