从 xaml 中清除 dependencyProperty 值

发布于 2024-12-13 03:57:54 字数 1058 浏览 0 评论 0原文

我有一个具有属性默认值的控件。当控件首次获取其 dataContext 设置时,它会自动分配此属性。

现在在 xaml 中,我希望能够取消设置此属性。我尝试将其设置为仅空字符串的 x:Null ,但随后出现错误,因为该属性没有转换器。在我希望禁用该功能的极少数情况下,如何简单地从 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 控件的默认值,并允许用户取消设置或将其更改为其他内容。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

我三岁 2024-12-20 03:57:54

这可能是不可能的,我最好的选择是:

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

但这会抛出“Cannot unset setter value”。因此,您最好反转逻辑或以其他方式保持属性未设置。

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.

小嗷兮 2024-12-20 03:57:54

就我个人而言,我会创建一个单独的依赖属性,例如 bool AutoBindValidation 并将其默认为 true。如果为 false,则当 DataContext 更改时不执行任何操作。这是更多的自我记录。根据您具体想要执行的操作,您可能根本不想公开公开 ContextValidationMessages

如果您确实想按照您发布的方式执行此操作,我不确定为什么将其设置为 {x:Null} 会导致错误(除非属性类型不可为空)。但这种方法会有问题,因为 DataContextChanged 将在解析 XAML 后发生。因此,用户可以将其设置为 {x:Null},但随后 DataContext 将发生更改,并且您的代码将设置默认绑定并践踏用户的值。您可以在控件的构造函数中设置绑定,但如果 DataContext 没有 ValidationMessages 属性,您的控件将抛出绑定错误。

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.

廻憶裏菂餘溫 2024-12-20 03:57:54

我认为 xaml 本身没有任何受支持的方法来执行此操作。在您的代码中,您将在 ContextValidationMessagesProperty 上设置本地值。您包含的样式设置器将具有较低的依赖属性优先级即使它们被评估,它们也会根据指定的值设置一个值 - 不清除它。也许您可以在 OmniBox 的默认样式中设置一个 Setter 来设置该属性,而不是在代码中设置绑定 - 例如,

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

如果您必须有条件地设置 Binding,那么您可以创建一个自定义 IValueConverter 来检查指定类型(作为范围)。例如

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 实例的样式设置为新样式,并确保 将 OverridesDefaultStyle 属性设置为 true

我想另一个选择是创建另一个依赖属性,它将在 ContextValidationMessages 属性上调用 ClearValue,但这似乎可能是一个维护问题。

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 - e.g.

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

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.

匿名的好友 2024-12-20 03:57:54

在某些情况下,您可以使用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>

即使窗口处于非活动状态,这似乎也足够聪明,可以继承正确的颜色。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文