简体   繁体   中英

Clear a dependencyProperty value from the xaml

I have a control which has a default value for a property. When the control first gets its dataContext set, it assigns this property automatically.

In the xaml now, I want it to be possible to UNset this property. I've tried setting it to x:Null of just the empty string, but then I get an error because there's no converter for the property. How do I simply unassign this property from the xaml in the rare cases where I want the feature disabled?

code where it is originally set:

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 where I want to unset the property.

<Style TargetType="ui:OmniBox">
    <Setter Property="ContextValidationMessages" Value="" />
</Style>

Note that if I do not set up the binding automatically when the data context changes, then by default there are no validation messages and I have to do the following in the xaml to set them up:

<Style TargetType="ui:OmniBox">
    <Setter Property="ContextValidationMessages" Value="ValidationMessages" />
</Style>

What I'm trying to do is make the above binding the default for my custom OmniBox control, and allow the user to unset it or change it to something else.

Personally, I would create a separate dependency property, such as bool AutoBindValidation and make it default to true. If it is false, don't do anything when the DataContext changes. This is a little more self-documenting. Depending on what exactly you're trying to do, you might not want to publicly expose ContextValidationMessages at all.

If you really want to do it the way you posted, I'm not sure why setting it to {x:Null} would cause an error (unless the property type is not nullable). But this approach would have problems because DataContextChanged is going to occur after the XAML is parsed. So the user can set it to {x:Null} , but then the DataContext will change and your code will set up the default binding and trample the user's value. You could set up the binding in the control's contstructor, but then if the DataContext does not have a ValidationMessages property, your control will be spitting out binding errors.

This may be impossible, my best bet was this:

<Setter Property="ContextValidationMessages"
        Value="{x:Static DependencyProperty.UnsetValue}" />

But that throws "Cannot unset setter value" . So you better inverse your logic or keep the property unset another way.

I don't think there is any supported way to do this in the xaml itself. In your code you are setting a local value on the ContextValidationMessagesProperty . The Style setters you included would have a lower dependency property precedence and even if they were evaluated they would set a value based on the specified Value - not clear it. Maybe instead of setting the binding in code you could have a Setter in your default style for OmniBox that sets that property - eg

<Setter Property="ContextValidationMessages" Value="{Binding ValidationMessages}" />

If you have to conditionally set the Binding then you could create a custom IValueConverter that checks for the specified type (passed as the parameter). eg

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;
    }
}

Then you might use it like this:

    <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>

In the case where you don't want this property to be applied you might set the Style for that instance of the OmniBox to a new style and make sure to set the OverridesDefaultStyle property to true .

I suppose another option is to create another dependency property that will call ClearValue on the ContextValidationMessages property but this seems like it could be a maintenance issue.

For certain cases you can 'reset' to the default value of the parent control by using a RelativeSource. For instance I'm using a DataGrid and this worked for me to reset back to the 'default'.

This is a textblock inside a datagrid cell.

<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>

This seems clever enough to inherit the correct color even when the window is inactive.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM