Search code examples
c#wpfxamldatatriggermultidatatrigger

WPF Enable Disable Border based on MultiDataTrigger not working


I have a border in WPF that I am trying to enable or disable based on two properties in the viewmodel: ConnectedVisibility and OperatingMode. This data trigger disables the border when connectedvisibility visibility is not set to "Visible". But it does not work for OperatingMode. For OperatingMode other than 0, the border should be disabled but it stays enabled. It appears that there is no impact of OperatingMode changing its value at all. Even the breakpoints that I put in the convertor are not being hit except when the program first starts up. The bindings look Ok as there is no problem shown in Debug output for these bindings. Any help is appreciated.

The Style is

<Style x:Key="EnableOnConnectBorderCorrected" TargetType="{x:Type Border}">
    <!--<Setter Property="BorderBrush" Value="#FFDADADA"/>-->
    <Setter Property="BorderBrush" Value="Red"/>
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="CornerRadius" Value="2"/>
    <Style.Triggers>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding ConnectedVisibility}" Value="Visible"/>
                <Condition Binding="{Binding OperatingMode}" Value="0"/>
            </MultiDataTrigger.Conditions>
            <Setter Property="IsEnabled" Value="True"/>
        </MultiDataTrigger>
        <DataTrigger Binding="{Binding OperatingMode, Converter={x:Static VM:IsEqualOrGreaterThanSHORTConverter.Instance}, ConverterParameter=1,Mode=TwoWay}" Value="True">
            <Setter Property="IsEnabled" Value="False"/>
        </DataTrigger>
        <DataTrigger Binding="{Binding ConnectedVisibility}" Value="Collapsed">
            <Setter Property="IsEnabled" Value="False"/>
        </DataTrigger>
    </Style.Triggers>
</Style>

The convertor used in the style is ->

public class IsEqualOrGreaterThanSHORTConverter : IValueConverter
{
    public static readonly IValueConverter Instance = new IsEqualOrGreaterThanSHORTConverter();

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        short iValue = (short)value;
        short compareToValue = System.Convert.ToInt16(parameter);

        return iValue >= compareToValue;
    }

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

The XAML where this style is applied is

<Border Name="RebootDash" Grid.Row="2" Grid.Column="1" Style="{StaticResource EnableOnConnectBorderCorrected}" BorderBrush="#FFDADADA" BorderThickness="1" CornerRadius="2" Width="Auto" Margin="0,1,1,0">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Border Grid.Row="2" Background="Wheat"/>
        <telerik:RadButton Command="{Binding ResetUnitCommand, Source={StaticResource UnitCommandProvider}}" Style="{StaticResource DashBoardImageButton}">
            <Image Grid.Row="0" Source="/Images/UnitManagementImages/IMG_THOR_UNITResetUnit128.png"
                   ToolTip="{x:Static properties:Resources.Unit_Command_ResetUnit}" 
                   Width="40" Height="40"
                   Margin="0,5,0,5"
                   HorizontalAlignment="Center"/>
        </telerik:RadButton>
        <TextBlock Grid.Row="2" Text="{x:Static properties:Resources.Unit_Command_ResetUnit}" HorizontalAlignment="Center" Margin="5,5,5,5"/>
    </Grid>
</Border>

The properties to which it is bound are

public Visibility ConnectedVisibility
{
    get { return connectedVisibility; }
    set
    {
        if (connectedVisibility == value) return;
        connectedVisibility = value;
        RaisePropertyChanged("ConnectedVisibility");
    }
}

public short OperatingMode
{
    get { return UnitOperatingModeVM.OperatingMode; }
    set
    {
        UnitOperatingModeVM.OperatingMode = value;
    }
}

Solution

  • since you have only one condition to enable the same, so perhaps setting IsEnabled to False by default should do the trick

    <Style x:Key="EnableOnConnectBorderCorrected" TargetType="{x:Type Border}">
        <!--<Setter Property="BorderBrush" Value="#FFDADADA"/>-->
        <Setter Property="BorderBrush" Value="Red"/>
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="CornerRadius" Value="2"/>
        <Setter Property="IsEnabled" Value="False"/>
        <Style.Triggers>
            <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                    <Condition Binding="{Binding ConnectedVisibility}" Value="Visible"/>
                    <Condition Binding="{Binding OperatingMode}" Value="0"/>
                </MultiDataTrigger.Conditions>
                <Setter Property="IsEnabled" Value="True"/>
            </MultiDataTrigger>
        </Style.Triggers>
    </Style>
    

    I have added <Setter Property="IsEnabled" Value="False"/> in the style which will by default disable the control and I have removed the other redundant conditions

    so as result when the both conditions in MultiDataTrigger will meet it will enable the same, otherwise it remains disabled

    above example assumes that both of the property in MultiDataTrigger ConnectedVisibility & OperatingMode are notifying the changes.


    you may also need to add the notification for OperatingMode in order for MultiDataTrigger to fire the trigger

    public short OperatingMode
    {
        get { return UnitOperatingModeVM.OperatingMode; }
        set
        {
            UnitOperatingModeVM.OperatingMode = value;
            RaisePropertyChanged("OperatingMode");
        }
    }