xaml usercontrol multidatatrigger from parent control and itself (usercontrol)

419 Views Asked by At

So I'm trying to learn how to dynamically apply style changes to controls. I have not been able to get a user control to change its borderbrush and background based off a radio button in the main window and the usercontrol's text property. Basing it just off the usercontrol's text property does seem to work. So it appears that I'm doing something wrong with getting the radio button's isCheck property.

I've simplified from the original code but this still shows the issue.

MainWindow.xaml

    <Window x:Class="UserControlTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:UserControlTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <RadioButton x:Name="calcPace" TabIndex="1" Content="Pace" HorizontalAlignment="Left" Margin="34,50,0,0" VerticalAlignment="Top" GroupName="CalculationType"
                     Height="16" Width="41"/>
        <RadioButton x:Name="calcDistance" TabIndex="2" Content="Distance" HorizontalAlignment="Left" Margin="80,50,0,0" VerticalAlignment="Top" GroupName="CalculationType"
                     Height="16" Width="61"/>
        <RadioButton x:Name="calcTime" TabIndex="3" Content="Time" HorizontalAlignment="Left" Margin="146,50,0,0" VerticalAlignment="Top" GroupName="CalculationType"
                     Height="16" Width="42"/>
        <local:TextBoxTime/>
    </Grid>
</Window>

TextBoxTime.xaml (usercontrol):

<UserControl x:Class="UserControlTest.TextBoxTime"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:UserControlTest"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<Grid>
    <TextBox x:Name="timeString" TabIndex="4" HorizontalAlignment="Left" Height="23" Margin="68,130,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120">
        <TextBox.Style>
            <Style TargetType="TextBox">
                <Setter Property="BorderBrush" Value="PaleGreen"/>
                <Setter Property="Background" Value="White"/>
                <Style.Triggers>
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition Binding="{Binding ElementName=calcTime, Path=IsChecked}" Value="False"/>
                            <Condition Binding="{Binding ElementName=timeString, Path=Text}" Value=""/>
                        </MultiDataTrigger.Conditions>
                        <Setter Property="BorderBrush" Value="Red"/>
                        <Setter Property="Background" Value="Snow"/>
                    </MultiDataTrigger>
                </Style.Triggers>
            </Style>
        </TextBox.Style>
    </TextBox>
</Grid>

Currently I've added no code behind for either.

Thanks

1

There are 1 best solutions below

0
On BEST ANSWER

Here's how I might do it:

public partial class RequireableTextBox : UserControl
{
    public RequireableTextBox()
    {
        InitializeComponent();
    }

    #region IsRequired Property
    public bool IsRequired
    {
        get { return (bool)GetValue(IsRequiredProperty); }
        set { SetValue(IsRequiredProperty, value); }
    }

    public static readonly DependencyProperty IsRequiredProperty =
        DependencyProperty.Register(nameof(IsRequired), typeof(bool), typeof(RequireableTextBox),
            new PropertyMetadata(false));
    #endregion IsRequired Property

    #region Text Property
    public String Text
    {
        get { return (String)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }

    public static readonly DependencyProperty TextProperty =
        DependencyProperty.Register(nameof(Text), typeof(String), typeof(RequireableTextBox),
            //  Default must be "" not null, for the trigger to understand
            new PropertyMetadata(""));
    #endregion Text Property
}

XAML

<UserControl 
    x:Class="UserControlTest.RequireableTextBox"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:local="clr-namespace:UserControlTest"
    mc:Ignorable="d" 
    d:DesignHeight="300" d:DesignWidth="300"
    IsTabStop="False"
    >
    <Grid>
        <TextBox 
            x:Name="timeString" 
            HorizontalAlignment="Left" 
            TextWrapping="Wrap" 
            VerticalAlignment="Top" 
            Width="120"
            Text="{Binding Text, RelativeSource={RelativeSource AncestorType=UserControl}, UpdateSourceTrigger=PropertyChanged}"
            >
            <TextBox.Style>
                <Style TargetType="TextBox">
                    <Setter Property="BorderBrush" Value="PaleGreen"/>
                    <Setter Property="Background" Value="White"/>

                    <Style.Triggers>
                        <!-- 
                        Seemed right to disable when unneeded; delete this trigger 
                        if you'd rather not.
                        -->
                        <DataTrigger 
                            Binding="{Binding IsRequired, RelativeSource={RelativeSource AncestorType=UserControl}}"
                            Value="False"
                            >
                            <Setter Property="IsEnabled" Value="False" />
                        </DataTrigger>

                        <MultiDataTrigger>
                            <MultiDataTrigger.Conditions>
                                <Condition 
                                    Binding="{Binding IsRequired, RelativeSource={RelativeSource AncestorType=UserControl}}" 
                                    Value="True"
                                    />
                                <Condition 
                                    Binding="{Binding Text, RelativeSource={RelativeSource AncestorType=UserControl}}" 
                                    Value=""
                                    />
                            </MultiDataTrigger.Conditions>
                            <Setter Property="BorderBrush" Value="Red"/>
                            <Setter Property="Background" Value="Snow"/>
                        </MultiDataTrigger>
                    </Style.Triggers>
                </Style>
            </TextBox.Style>
        </TextBox>
    </Grid>
</UserControl>

Usage:

<StackPanel>
    <RadioButton x:Name="calcTime" GroupName="CalculationType">Calculate Time</RadioButton>
    <RadioButton x:Name="calcDistance" GroupName="CalculationType">Calculate Distance</RadioButton>
    <local:RequireableTextBox
        IsRequired="{Binding IsChecked, ElementName=calcTime}"
        />
    <local:RequireableTextBox
        x:Name="DistanceValue"
        IsRequired="{Binding IsChecked, ElementName=calcDistance}"
        />
    <!-- Just tossed this in to demonstrate the Text property -->
    <Label Content="{Binding Text, ElementName=DistanceValue}" Foreground="Gray" />
</StackPanel>