Search code examples
c#wpfuser-controls

How can I make this decorated Label control work?


I feel like this should have been a simple thing, but obviously I'm doing something dumb.

I am trying to make a UserControl with a DependencyProperty (an enum) that controls whether it simply displays the text supplied in its Content property verbatim, or appends it with some additional text.

UserControl:

<UserControl x:Class="Controls.UserControls.IndicatorLabel"
             x:Name="indicatorLabel"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:enum="clr-namespace:MyNamespace;assembly=EnumAssembly">
    <Label>
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="{Binding Content, ElementName=indicatorLabel}" />
            <TextBlock FontStyle="Italic"
                       Margin="5,0,0,0">
                <TextBlock.Style>
                    <Style TargetType="TextBlock">
                        <Setter Property="Visibility"
                                Value="Collapsed" />
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding IndicatorType}"
                                         Value="{x:Static enum:LabelIndicator.Optional}">
                                <Setter Property="Text"
                                        Value="(Optional)" />
                                <Setter Property="Visibility"
                                        Value="Visible" />
                            </DataTrigger>
                            <DataTrigger Binding="{Binding IndicatorType}"
                                         Value="{x:Static enum:LabelIndicator.Required}">
                                <Setter Property="Text"
                                        Value="(Required)" />
                                <Setter Property="Visibility"
                                        Value="Visible" />
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </TextBlock.Style>
            </TextBlock>
        </StackPanel>
    </Label>
</UserControl>

UserControl's code-behind:

public partial class IndicatorLabel : UserControl
    {
        public static DependencyProperty IndicatorTypeProperty = DependencyProperty.Register("IndicatorType", typeof(LabelIndicator), typeof(IndicatorLabel));
        public LabelIndicator IndicatorType
        {
            get => (LabelIndicator)GetValue(IndicatorTypeProperty);
            set => SetValue(IndicatorTypeProperty, value);
        }

        public IndicatorLabel()
        {
            InitializeComponent();
        }
    }

Usage of the UserControl in another XAML page:

<uc:IndicatorLabel Grid.Row="4"
                   Content="Description"
                   IndicatorType="Optional" />

I expected to see: Description (Optional)

In fact, I haven't been able to get what's in the UserControl's XAML to have any affect at all, so long as the Content property is set.

EDIT:

The reason I say it has no effect is because even if put a literal string in the Text property of the first TextBlock, whatever is in the Content property still displays. It seems as if neither TextBlock is truly showing.

So why is this happening? Is it not possible to use the Content property as a way to get text into the parts that I really mean to display? Am I breaking some WPF rule about Content here?


Solution

  • First off; yes you don't want to use Content. What your XAML for your UC really says is:

    <UserControl>
        <UserControl.Content>
            ... All that stuff
        </UserControl.Content>
    </UserControl>
    

    So when you assign Content in the parent XAML you are just overwriting all that. Use a different property (like "Text") instead. If instead of UserControl you did an actual Control (with separate ControlTemplate and everything) then you could use that name

    Also, the {Binding IndicatorType} is looking at the inherited data context. You should either set the User Control's data context to itself or use x:Reference to tell it to look at the user control itself.