C# 防止IValueConverter设置本地值

C# 防止IValueConverter设置本地值,c#,wpf,C#,Wpf,短版本: 在绑定中使用IValueConverter时,WPF似乎总是设置本地值,即使该转换器返回binding.DoNothing 我的问题是:我必须返回什么,或者如何告诉WPF使用继承的值 请注意:我不想使用DataTriggers,因为这会大大增加我的代码,因为对于当前转换器返回的每种颜色,我都需要一个数据触发器和一个转换器 带复制的长版本: 想象以下场景: 我有一个按钮,其中有一个文本块。按钮存在一种设置前台属性的样式。此值由文本块继承。 现在我想创建一个值转换器,将TextBlock

短版本:
在绑定中使用
IValueConverter
时,WPF似乎总是设置本地值,即使该转换器返回
binding.DoNothing

我的问题是:我必须返回什么,或者如何告诉WPF使用继承的值

请注意:我不想使用DataTriggers,因为这会大大增加我的代码,因为对于当前转换器返回的每种颜色,我都需要一个数据触发器和一个转换器


带复制的长版本:

想象以下场景:
我有一个
按钮
,其中有一个
文本块
按钮
存在一种设置
前台
属性的样式。此值由
文本块继承。
现在我想创建一个值转换器,将
TextBlock
的值转换为
画笔
,用作
前景
——但仅在某些情况下。在我不想设置特殊颜色的情况下,我返回
Binding.DoNothing
。我的理解是,这将使
TextBlock
继续使用继承的值

不幸的是,我的理解是不正确的。即使返回
Binding.DoNothing
时,也会设置本地值。这已通过Snoop验证

这个简单的例子很容易再现这个问题:

XAML:

如您所见,第一个按钮具有黑色文本而不是红色文本。如果删除
TextBlock
的样式,两个按钮都将具有正确的红色文本

问题:

我该怎么做才能防止这种情况?是否有一些值要返回,告诉引擎继续使用继承的值?

我已经让它工作了,但是这个解决方案不好,而且有点味道。。。尽管如此,我还是会发布它

声明自定义附加属性,如下所示:

 public static class CustomForeground
{
    public static readonly DependencyProperty CustomForegroundProperty = DependencyProperty.RegisterAttached(
                      "CustomForeground",
                      typeof(Brush),
                      typeof(CustomForeground),
                      new FrameworkPropertyMetadata(Brushes.Black, FrameworkPropertyMetadataOptions.AffectsRender, OnChange));

    public static void SetCustomForeground(UIElement element, Brush value)
    {
        element.SetValue(CustomForegroundProperty, value);
    }

    public static void OnChange(DependencyObject d, DependencyPropertyChangedEventArgs arg)
    {
        if (arg.NewValue != null)
            d.SetValue(TextBlock.ForegroundProperty, arg.NewValue);
    }
}
和文本框样式:

<Style TargetType="{x:Type TextBlock}">
        <Setter Property="WpfApplication1:CustomForeground.CustomForeground"
              Value="{Binding Path=Text, RelativeSource={RelativeSource Self}, Converter={StaticResource DummyConverter}}" />
    </Style>


这是我目前唯一想到的事情,假设你的按钮文本不变,它就会起作用。如果是,您需要记住另一个附加属性中前台的默认值,并在else语句中设置它。

我已经让它工作了,但这个解决方案不好,而且有点味道。。。尽管如此,我还是会发布它

声明自定义附加属性,如下所示:

 public static class CustomForeground
{
    public static readonly DependencyProperty CustomForegroundProperty = DependencyProperty.RegisterAttached(
                      "CustomForeground",
                      typeof(Brush),
                      typeof(CustomForeground),
                      new FrameworkPropertyMetadata(Brushes.Black, FrameworkPropertyMetadataOptions.AffectsRender, OnChange));

    public static void SetCustomForeground(UIElement element, Brush value)
    {
        element.SetValue(CustomForegroundProperty, value);
    }

    public static void OnChange(DependencyObject d, DependencyPropertyChangedEventArgs arg)
    {
        if (arg.NewValue != null)
            d.SetValue(TextBlock.ForegroundProperty, arg.NewValue);
    }
}
和文本框样式:

<Style TargetType="{x:Type TextBlock}">
        <Setter Property="WpfApplication1:CustomForeground.CustomForeground"
              Value="{Binding Path=Text, RelativeSource={RelativeSource Self}, Converter={StaticResource DummyConverter}}" />
    </Style>


这是我目前唯一想到的事情,假设你的按钮文本不变,它就会起作用。如果是,您需要记住另一个附加属性中前台的默认值,并在else语句中进行设置。

回答您的问题:根据thread,否。只要您给TextBlock一个样式设置器(#4),返回的任何值都将覆盖继承的属性(#7)

相反,您可以创建如下的多重绑定:

public class DummyConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (values[0].ToString() == "Text2")
            return Brushes.Cyan;

        return values[1];
    }
}

<Window x:Class="Spritefire.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:Spritefire"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <local:DummyConverter x:Key="DummyConverter" />
        <Style TargetType="{x:Type Button}">
            <Setter Property="Foreground" Value="Red" />
        </Style>
        <Style TargetType="{x:Type TextBlock}">
            <Setter Property="Foreground">
                <Setter.Value>
                    <MultiBinding Converter="{StaticResource DummyConverter}">
                        <Binding Path="Text" RelativeSource="{RelativeSource Self}" />
                        <Binding Path="Foreground" ElementName="ExampleButton" />
                    </MultiBinding>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <StackPanel>
        <Button x:Name="ExampleButton">
            <TextBlock>Text1</TextBlock>
        </Button>
        <Button>
            <TextBlock>Text2</TextBlock>
        </Button>
    </StackPanel>
</Window>
公共类DummyConverter:IMultiValueConverter
{
公共对象转换(对象[]值,类型targetType,对象参数,System.Globalization.CultureInfo区域性)
{
如果(值[0].ToString()=“Text2”)
返回刷。青色;
返回值[1];
}
}
文本1
文本2

回答您的问题:根据thread,答案是否定的。只要您给TextBlock一个样式设置器(#4),返回的任何值都将覆盖继承的属性(#7)

相反,您可以创建如下的多重绑定:

public class DummyConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (values[0].ToString() == "Text2")
            return Brushes.Cyan;

        return values[1];
    }
}

<Window x:Class="Spritefire.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:Spritefire"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <local:DummyConverter x:Key="DummyConverter" />
        <Style TargetType="{x:Type Button}">
            <Setter Property="Foreground" Value="Red" />
        </Style>
        <Style TargetType="{x:Type TextBlock}">
            <Setter Property="Foreground">
                <Setter.Value>
                    <MultiBinding Converter="{StaticResource DummyConverter}">
                        <Binding Path="Text" RelativeSource="{RelativeSource Self}" />
                        <Binding Path="Foreground" ElementName="ExampleButton" />
                    </MultiBinding>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <StackPanel>
        <Button x:Name="ExampleButton">
            <TextBlock>Text1</TextBlock>
        </Button>
        <Button>
            <TextBlock>Text2</TextBlock>
        </Button>
    </StackPanel>
</Window>
公共类DummyConverter:IMultiValueConverter
{
公共对象转换(对象[]值,类型targetType,对象参数,System.Globalization.CultureInfo区域性)
{
如果(值[0].ToString()=“Text2”)
返回刷。青色;
返回值[1];
}
}
文本1
文本2

如果使用relativesource将convertparameter绑定添加到父级的前台,该怎么办。您可以返回父前景,而不是Binding.DoNothing。平心而论,我不知道它是否有效。@blindmeis:这是我尝试的第一件事之一:-)不幸的是,您不能在
ConverterParameter
中使用绑定。如果您将ConverterParameter绑定添加到具有relativesource的父级的前台,该怎么办。您可以返回父前景,而不是Binding.DoNothing。平心而论,我不知道它是否有效。@blindmeis:这是我第一次尝试的事情之一:-)不幸的是,你不能在
转换器参数
中使用绑定。谢谢,看起来不错。但是,它仅适用于可以设置父级名称的情况。在我的实际应用程序中,我不能这样做,因为我没有
按钮
文本块
,但我有属于生成布局的数据网格的类。我无法在那里输入姓名。不过,您可以使用这样的相对源代码:
谢谢,看起来不错。但是,它仅适用于可以设置父级名称的情况。在我的实际应用程序中,我不能这样做,因为我没有
按钮
文本块
,但我有属于生成布局的数据网格的类。我无法在那里输入姓名。但是,您可以使用这样的相对源:
确实:dirty:-)谢谢!的确:肮脏:-)不过还是谢谢你!