我们有一个可能会或可能不会在弹出控件中托管的控件。在它的情况下,我们想要使用RelativeSource和OneWayToSource绑定在弹出窗口上设置属性。如果它没有托管在弹出窗口中,我们希望绑定基本上被忽略/什么都不做。
我唯一想到的就是使用自定义转换器绑定到self,该转换器在内部遍历可视树寻找弹出窗口。如果找到了,那就去做吧。如果没有,什么也不做。但我想知道它是否可以完全用XAML绑定语法完成。
答案 0 :(得分:0)
请尝试以下代码:
<Border>
<TextBlock>
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Text" Value="Exists"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=StackPanel}}" Value="{x:Null}">
<Setter Property="Text" Value="No stackpanel"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Border>
它将同时显示&#34; No stackpanel&#34;和输出窗口中的错误。如果你把StackPanel放在Border&#34; Exists&#34;将显示。在满足条件时,在DataTrigger中设置您想要的任何内容。
如果您想避免收到错误:
<Window.Resources>
<local:IsParentTypePresentToBoolConverter x:Key="IsParentTypePresentToBoolConverter"/>
</Window.Resources>
<Border>
<TextBlock>
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Text" Value="No StackPanel"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self},
Converter={StaticResource IsParentTypePresentToBoolConverter}}" Value="True">
<Setter Property="Text" Value="Stackpanel exists as parent"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Border>
转换器,它检测这种类型是否作为父类存在:
class IsParentTypePresentToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var isPresent = FindParent<StackPanel>((DependencyObject) value);
return isPresent != null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
private T FindParent<T>(DependencyObject child) where T : DependencyObject
{
var parentObject = VisualTreeHelper.GetParent(child);
if (parentObject == null) return null;
var parent = parentObject as T;
return parent?? FindParent<T>(parentObject);
}
}
在这里你有更多的通用等价物,你可以使用反射来找到父类型。
class IsParentTypePresentToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var method = GetType().GetMethod("FindParent").MakeGenericMethod(new Type[1] { (Type)parameter });
var foundObject = method.Invoke(this, new object[] { (DependencyObject)value });
return foundObject != null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
public T FindParent<T>(DependencyObject child) where T : DependencyObject
{
var parentObject = VisualTreeHelper.GetParent(child);
if (parentObject == null) return null;
var parent = parentObject as T;
return parent ?? FindParent<T>(parentObject);
}
}
XAML中唯一的区别是您指示搜索对象类型。
<Border>
<TextBlock>
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Text" Value="No StackPanel"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self},
Converter={StaticResource IsParentTypePresentToBoolConverter},
ConverterParameter={x:Type Border}}" Value="True">
<Setter Property="Text" Value="Stackpanel exists as parent"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Border>
答案 1 :(得分:0)
如果它没有托管在弹出窗口中,我们希望绑定基本上被忽略/什么都不做。
由于你有一个控件,你可以创建一个布尔依赖属性,一个标志,它可以触发两个隐藏控件中的一个,这些控件由于设置布尔值的方式而以特定方式运行。
我称之为标准方式,因为控件不需要了解消费者的任何信息,消费者指定状态。
使用RelativeSource和OneWayToSource绑定在弹出窗口上设置属性。
与上面类似,使用两个不同的隐藏控件,然后使用样式查找特定窗口和特定属性。然后根据找到的内容隐藏或显示控件:
<Setter Property="IsEnabled" Value="False" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsPopup,
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Page}}}"
Value="True">
<Setter Property="IsEnabled"
Value="True" />
</DataTrigger>
</Style.Triggers>