我有一个控件,它具有属性的默认值。当控件首先设置其dataContext时,它会自动分配此属性。
现在在xaml中,我希望它可以UNset这个属性。我已经尝试将它设置为x:只是空字符串的空,但后来我得到一个错误,因为该属性没有转换器。在我希望禁用该功能的极少数情况下,如何从xaml中取消分配此属性?
最初设置的代码:
void OmniBox_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if( e.NewValue is BindingObjectBaseExtended )
{
BindingObjectBaseExtended value = (BindingObjectBaseExtended)e.NewValue;
this.SetBinding(OmniBox.ContextValidationMessagesProperty, new Binding() { Source = value, Path = new PropertyPath("ValidationMessages") });
}
}
xaml我要取消设置属性。
<Style TargetType="ui:OmniBox">
<Setter Property="ContextValidationMessages" Value="" />
</Style>
请注意,如果我在数据上下文更改时没有自动设置绑定,那么默认情况下没有验证消息,我必须在xaml中执行以下操作来设置它们:
<Style TargetType="ui:OmniBox">
<Setter Property="ContextValidationMessages" Value="ValidationMessages" />
</Style>
我要做的是将上面的绑定设置为我的自定义OmniBox控件的默认值,并允许用户取消设置或将其更改为其他内容。
答案 0 :(得分:4)
DependencyProperty.UnsetValue不能在XAML中使用。
http://msdn.microsoft.com/en-us/library/system.windows.dependencyproperty.unsetvalue(v=vs.90).ASPX
答案 1 :(得分:2)
就个人而言,我会创建一个单独的依赖项属性,例如bool AutoBindValidation
,并使其默认为true。如果为false,则在DataContext更改时不要执行任何操作。这是一个更自我记录。根据您的具体操作,您可能根本不想公开ContextValidationMessages
。
如果你真的想按照你发布的方式去做,我不确定为什么将它设置为{x:Null}
会导致错误(除非属性类型不可为空)。但是这种方法会有问题,因为在解析XAML之后会发生DataContextChanged
。因此,用户可以将其设置为{x:Null}
,但随后DataContext将更改,您的代码将设置默认绑定并践踏用户的值。您可以在控件的contstructor中设置绑定,但如果DataContext没有ValidationMessages
属性,则您的控件将吐出绑定错误。
答案 2 :(得分:1)
这可能是不可能的,我最好的选择是:
<Setter Property="ContextValidationMessages"
Value="{x:Static DependencyProperty.UnsetValue}" />
但是这会引发"Cannot unset setter value"
。所以你最好改变你的逻辑,或者以另一种方式保持财产不变。
答案 3 :(得分:1)
我认为在xaml本身中没有任何支持的方法可以做到这一点。在您的代码中,您要在 ContextValidationMessagesProperty 上设置本地值。您包含的样式设置器将具有较低的dependency property precedence,即使它们被评估,它们也会根据指定的值设置一个值 - 不清楚它。也许不是在代码中设置绑定,而是可以在OmniBox的默认样式中设置Setter来设置该属性 - 例如。
<Setter Property="ContextValidationMessages" Value="{Binding ValidationMessages}" />
如果必须有条件地设置Binding,则可以创建一个自定义IValueConverter来检查指定的类型(作为参数传递)。 e.g。
public class IsAssignableFromConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Type typeParameter = parameter as Type;
if (typeParameter == null)
return DependencyProperty.UnsetValue;
return value != null && typeParameter.IsAssignableFrom(value.GetType());
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
然后你可以像这样使用它:
<local:IsAssignableFromConverter x:Key="isAssignableConverter" />
<Style TargetType="ui:OmniBox">
<Style.Triggers>
<DataTrigger Binding="{Binding Converter={StaticResource isAssignableConverter}, ConverterParameter={x:Type ui:BindingObjectBaseExtended}}" Value="True">
<Setter Property="ContextValidationMessages" Value="{Binding ValidationMessages}" />
</DataTrigger>
</Style.Triggers>
</Style>
如果您不希望应用此属性,则可以将OmniBox的该实例的样式设置为新样式,并确保set the OverridesDefaultStyle property to true。
我想另一种选择是创建另一个依赖属性,它将在ContextValidationMessages属性上调用ClearValue,但这似乎可能是一个维护问题。
答案 4 :(得分:0)
在某些情况下,您可以使用 RelativeSource 将“重置”为父控件的默认值。例如,我使用的是 DataGrid,这对我重置回“默认值”很有用。
这是数据网格单元内的文本块。
<TextBlock Text="{Binding ServiceName}">
<TextBlock.Style>
<Style>
<Style.Triggers>
<!-- Change text color to purple for FedEx -->
<Trigger Property="TextBlock.Text" Value="FedEx">
<Setter Property="TextBlock.Foreground" Value="Purple"/>
</Trigger>
<!-- Reset if the cell is selected, since purple on blue is illegible -->
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridCell}}}" Value="True">
<Setter Property="TextBlock.Foreground" Value="{Binding Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGridCell}}}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
这似乎很聪明,即使窗口处于非活动状态,也能继承正确的颜色。