繁体   English   中英

WPF绑定:退回到样式中定义的值

[英]WPF Binding: Fallback to value defined in Style

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一样神奇。

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

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

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
        {
            // ...
        }
    }
}

基本上,您不能明确回退。 最好的选择是仅在您确实要为状态设置颜色时才有条件地设置颜色。 这可以通过样式触发器来完成。 这是一个基于文本框文本不为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)返回具有自定义状态颜色的Brush

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

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

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

首先,您将需要一个与建议的@ grek40类似的转换器,但有可能深入到另一个转换器。 请注意,此转换器依赖于状态-画笔转换器,当不设置颜色时返回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>

这将不起作用,因为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 ,因此,如果值为False则甚至不会评估Background的第二个设置器:

<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值为false, IsStale忽略第二个设置器。

附录A:支持源代码

转换器:

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

这介于.Resources标签之间:

<colorBrushes:BooleanToBrushConverter x:Key="IsStaleToBackgroundConverter" 
                                      TrueBrush="{StaticResource RedStaleBrush}" 
                                      FalseBrush="{StaticResource TransparentBrush}" 
                                      DefaultBrush="{StaticResource TransparentBrush}" />

您还必须定义颜色,或将其替换为常量,例如DefaultBrush="Green"

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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