如何根据自定义控件的属性更改其背景颜色

4

我有一个简单的自定义控件,用于向用户显示消息(类似于浏览器的信息栏)。

我添加了一个布尔类型的依赖属性,用于指示错误消息。如果标志位被设置为真,则控件的背景颜色应该是红色,否则为黄色。

这是控件的样式(在Themes\Generic.xaml中):

<Style TargetType="{x:Type local:InfoBar}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:InfoBar}">
                <ControlTemplate.Triggers>
                    <Trigger Property="IsError" Value="True" >
                             <Setter Property="Background" Value="LightPink" />
                    </Trigger>
                    <Trigger Property="IsError" Value="False" >
                             <Setter Property="Background" Value="LightYellow" />
                    </Trigger>                  
                </ControlTemplate.Triggers>

                <Grid Margin="4,0,4,0">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*" />
                        <ColumnDefinition Width="auto" />
                    </Grid.ColumnDefinitions>
                    <TextBlock Text="{TemplateBinding Message}" Padding="5" FontWeight="Normal" TextWrapping="Wrap" Grid.Column="0"/>
                    <Button x:Name="PART_CloseButton" Grid.Column="1" VerticalAlignment="Top"  >
                        <Button.Template>
                            <ControlTemplate>
                                <Border HorizontalAlignment="Center" VerticalAlignment="Center" BorderBrush="Transparent">
                                    <Image Height="16" Width="16" Source="/QOffice.Common.Controls;component/Images/icons/Close.png"  />
                                </Border>
                            </ControlTemplate>
                        </Button.Template>
                    </Button>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

这里是控件本身:

[TemplatePart(Name = PART_CloseButton, Type = typeof(ButtonBase))]
public class InfoBar : Control
{

    private const string PART_CloseButton = "PART_CloseButton";

    static InfoBar()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(InfoBar), new FrameworkPropertyMetadata(typeof(InfoBar)));

    }

    #region CloseButton

    private ButtonBase _closeButton;
    /// <summary>
    /// Gets or sets the CloseButton template part.
    /// </summary>
    private ButtonBase CloseButton
    {
        get
        {
            return _closeButton;
        }
        set
        {
            if (_closeButton != null)
            {
                _closeButton.Click -= OnButtonClick;
            }

            _closeButton = value;

            if (_closeButton != null)
            {
                _closeButton.Click += OnButtonClick;
            }
        }
    }

    private void OnButtonClick(object sender, RoutedEventArgs e)
    {
        this.Visibility = System.Windows.Visibility.Collapsed;
    }


    #endregion 


    public override void OnApplyTemplate()
    {
        CloseButton = GetTemplateChild(PART_CloseButton) as ButtonBase;


    }


    #region DependencyProperty Message of InfoBar

    public string Message
    {
        get { return (string)GetValue(MessageProperty); }
        set { SetValue(MessageProperty, value); }
    }

    public static readonly DependencyProperty MessageProperty =
        DependencyProperty.Register("Message", typeof(string), typeof(InfoBar),
                new UIPropertyMetadata());

    #endregion


    #region DependencyProperty IsError of InfoBar

    public bool IsError
    {
        get { return (bool)GetValue(IsErrorProperty); }
        set { SetValue(IsErrorProperty, value); }
    }

    public static readonly DependencyProperty IsErrorProperty =
        DependencyProperty.Register("IsError", typeof(bool), typeof(InfoBar),
                new UIPropertyMetadata());

    #endregion





}

正如您所看到的,我定义了一个属性IsError和一个触发器来设置控件的背景。但是背景一直是透明的。除此之外,控件是有功能的。

问题出在哪里?


你尝试过将触发器放在VisualTree中更低的位置,比如直接放在网格上吗? - Damascus
3个回答

3

看起来你的自定义控件即使我手动添加背景颜色也无法正确设置背景颜色。我不确定为什么会这样,希望有人能详细解释一下。但是我已经通过使用以下代码更改样式中网格的颜色来解决了你的问题:

<Grid.Style>
    <Style TargetType="{x:Type Grid}">
        <Style.Triggers>
            <DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:InfoBar}}, Path=IsError}" Value="True">
                <Setter Property="Background" Value="LightPink" />
            </DataTrigger>
            <DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:InfoBar}}, Path=IsError}" Value="False">
                <Setter Property="Background" Value="LightYellow" />
            </DataTrigger>
        </Style.Triggers>
    </Style>
</Grid.Style>

这会根据您的InfoBar控件中的IsError值触发网格的背景颜色。


谢谢 - 在网格上设置属性而不是控件本身可行。 - Michael D.

2

您给Control设置了Background,但没有任何子元素使用它。有两种可能的解决方案:

  1. TemplateBinding

    <Grid Margin="4,0,4,0" Background="{TemplateBinding Background}">
    
  2. DataTrigger with TargetName

    <ControlTemplate TargetType="{x:Type local:InfoBar}">
        <Grid Name="grid" Margin="4,0,4,0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="auto" />
            </Grid.ColumnDefinitions>
            ...
        </Grid>
        <ControlTemplate.Triggers>
            <Trigger Property="IsError" Value="True" >
                <Setter TargetName="grid" Property="Background" Value="LightPink" />
            </Trigger>
            <Trigger Property="IsError" Value="False" >
                <Setter TargetName="grid" Property="Background" Value="LightYellow" />
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>
    

    In this solution you have to change the order: ControlTemplate.Triggers after Grid declaration.

  1. TemplateBinding

    <Grid Margin="4,0,4,0" Background="{TemplateBinding Background}">
    
  2. 带有TargetNameDataTrigger

    <ControlTemplate TargetType="{x:Type local:InfoBar}">
        <Grid Name="grid" Margin="4,0,4,0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="auto" />
            </Grid.ColumnDefinitions>
            ...
        </Grid>
        <ControlTemplate.Triggers>
            <Trigger Property="IsError" Value="True" >
                <Setter TargetName="grid" Property="Background" Value="LightPink" />
            </Trigger>
            <Trigger Property="IsError" Value="False" >
                <Setter TargetName="grid" Property="Background" Value="LightYellow" />
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>
    

    在此解决方案中,您需要更改顺序:Grid声明后的ControlTemplate.Triggers


0
尝试这个(因为IsError是您InfoBar中的DP,而不是ControlTemplate的属性)
<DataTrigger Property="{Binding IsError, RelativeSource={RelativeSource
                                         Mode=TemplatedParent}" Value="True">
      <Setter Property="Background" Value="LightPink" />
</DataTrigger>
<DataTrigger Property="{Binding IsError, RelativeSource={RelativeSource
                                      Mode=TemplatedParent}" Value="False">
      <Setter Property="Background" Value="LightYellow" />
</DataTrigger> 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接