WPF绑定:回退到样式

时间:2017-09-18 10:32:08

标签: c# wpf binding

WPF颜色绑定如何回退到默认值?

以下是我要做的事情:

<TextBox Text="Some Binding"/>

将生成一个文本框,其中某些背景颜色在其他地方定义。

<Textbox Text="Some Binding" 
  Background = "{Binding Path=Status, 
  TargetNullValue='Same color as the Textbox above, please', 
  Converter=***}"/>

这个文本框应该根据状态(工作正常)改变颜色,但对于某些值,我希望背景恢复到没有绑定的情况下使用的颜色。

其他信息:我在资源字典中使用这些文本框。

<ResourceDictionary>
  <Style TargetType=**MyTreeControl**>
    <Style.Resources>
      <HierarchicalDataTemplate ***>
        <Textboxes from above/>

非常感谢!

编辑:最后我使用了@ Mike的解决方案,我发现它非常优雅。

然而,我很感兴趣为什么这个有效,而昨天这不是

<DataTrigger  Binding="{Binding Path=Status }" Value="1">
                <Setter Property="Background" Value="Lime"/>
              </DataTrigger>
              <DataTrigger  Binding="{Binding Path=Status }" Value="2">
                <Setter Property="Background" Value="Red"/>
              </DataTrigger>

再次尝试,今天它也运作良好。看起来像WPF魔术对我来说。

4 个答案:

答案 0 :(得分:0)

  

但是对于某些值,我希望背景恢复为颜色

将此逻辑放在转换器中(因为您已经使用过它)。

public class MyStatusToBackgroundConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        Status status = (Status)value;

        // maybe use a switch statement depending on number of cases?
        if (status == Status.SomeValue || status == Status.SomeOtherValue)
            return Brushes.Brushes.Transparent;
        else
        {
            // ...
        }
    }
}

答案 1 :(得分:0)

基本上,你不能明确地退缩。您最好的选择可能是仅在您确实要为状态设置一个颜色时有条件地设置颜色。这可以使用样式触发器完成。这是一个基于文本框文本不为null或为空而执行类似操作的示例:

<Window.Resources>
    <!-- emulate some default style -->
    <Style TargetType="{x:Type TextBox}">
        <Setter Property="Background" Value="Yellow"/>
    </Style>

    <local:TestColorConverter x:Key="colorConverter"/>
</Window.Resources>
<!-- ... -->

    <TextBox Text="a Status">
        <TextBox.Style>
            <Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Text,RelativeSource={RelativeSource Self},Converter={StaticResource colorConverter},ConverterParameter='Check'}" Value="True">
                        <Setter Property="Background" Value="{Binding Text,RelativeSource={RelativeSource Self},Converter={StaticResource colorConverter}}"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </TextBox.Style>
    </TextBox>

转换器有两种模式:(1)返回True / False以指示状态是否具有自定义颜色(2)返回具有自定义状态颜色的画笔

public class TestColorConverter : IValueConverter
{
    // the question doesn't explain the status type, so I use string.
    // probably replace string with your actual status type

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (string.Equals("Check", parameter as string))
        {
            return HasColor(value as string);
        }
        return GetColor(value as string);
    }

    private bool HasColor(string status)
    {
        return GetColor(status) != null;
    }

    private Brush GetColor(string status)
    {
        if (string.IsNullOrWhiteSpace(status))
        {
            return null;
        }
        if (status.StartsWith("a"))
        {
            return Brushes.Red;
        }
        return Brushes.DarkGoldenrod;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

答案 2 :(得分:0)

您尝试做的事情很棘手,因为您在Binding上设置的任何Background都将优先于原本应用的值。

您需要的是有条件地设置Binding的方法。 @ grek40的解决方案在正确的轨道上,但条件逻辑需要评估建议绑定的输出而不是输入到该绑定。

首先,您需要一个类似于@ grek40提议的转换器,但有可能深入到另一个转换器。请注意,当不应设置颜色时,此转换器依赖于Status-to-Brush转换器返回 null

public class IsNotNullConverter : IValueConverter
{
    public IValueConverter InnerConverter { get; set; }

    public object Convert(
        object value,
        Type targetType,
        object parameter,
        CultureInfo culture)
    {
        if (InnerConverter != null)
            value = InnerConverter.Convert(value, targetType, parameter, culture);
        return value != null &&
               value != DependencyProperty.UnsetValue;
    }

    public object ConvertBack(
        object value,
        Type targetType,
        object parameter,
        CultureInfo culture)
    {
        return Binding.DoNothing;
    }
}

在声明文本框的模板中,您需要一个有条件地应用Background绑定的触发器:

<DataTemplate>
  <DataTemplate.Resources>
    <l:StatusToBrushConverter x:Key="StatusConverter" />
    <l:IsNotNullConverter x:Key="ShouldApplyStatusConverter"
                          InnerConverter="{StaticResource StatusConverter}" />
  </DataTemplate.Resources>
  <TextBox x:Name="_textBox" />
  <DataTemplate.Triggers>
    <DataTrigger Binding="{Binding Path=Status,
                                   Converter={StaticResource ShouldApplyStatusConverter}}"
                 Value="True">
      <Setter TargetName="_textBox"
              Property="Background"
              Value="{Binding Path=Status,
                              Converter={StaticResource StatusConverter}}" />
    </DataTrigger>
  </DataTemplate.Triggers>
</DataTemplate>

答案 3 :(得分:0)

这将不起作用,因为Background的第二个设置器将始终覆盖第一个设置器:

<!-- Set the background based on the level into the tree. -->
<Setter Property="Background" Value="{Binding DataItem.Level, Converter={StaticResource IntegerToBrushConverter}}"/>
<!-- Row is red if no live updates received for N seconds -->
<Setter Property="Background" Value="{Binding DataItem.IsStale, Converter={StaticResource IsStaleToBackgroundConverter}}"/>    

要解决此问题,请包裹在DataTrigger中,因此即使Background的值是False也不会评估<Setter Property="Background" Value="{Binding DataItem.Level, Converter={StaticResource IntegerToBrushConverter}}"/> <!-- Row is red if no live updates received for N seconds --> <Style.Triggers> <DataTrigger Binding="{Binding DataItem.IsStale}" Value="True"> <Setter Property="Background" Value="{Binding DataItem.IsStale, Converter={StaticResource IsStaleToBackgroundConverter}}"/> </DataTrigger> </Style.Triggers> 的第二个设置器:

Background

这意味着将应用IsStale的第一个设置器,如果public class BooleanToBrushConverter : ValueConverterBase { public Brush TrueBrush { get; set; } public Brush FalseBrush { get; set; } public Brush DefaultBrush { get; set; } public override object Convert(object value, Type targetType, object parameter, CultureInfo culture) { try { if (value==null) { return null; } var booleanValue = (bool)value; return booleanValue ? this.TrueBrush : this.FalseBrush; } catch (InvalidCastException) { return this.DefaultBrush; } } } 的值为false,则将忽略第二个设置器。

附录A:支持的源代码

转换器:

.Resources

这在<colorBrushes:BooleanToBrushConverter x:Key="IsStaleToBackgroundConverter" TrueBrush="{StaticResource RedStaleBrush}" FalseBrush="{StaticResource TransparentBrush}" DefaultBrush="{StaticResource TransparentBrush}" /> 标签之间:

DefaultBrush="Green"

您还必须定义颜色,或将其替换为常量,例如Windows 10 x64 1903