Pablo
Pablo

Reputation: 11

Data Trigger not firing

I have a custom user control that exposes two dependency properties, IsBusy and BusyText.

What I want is for the control to appear when IsBusy is set to true... Here's the xaml for the user control

<UserControl x:Class="MyNamespace.BusyDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:MyNamespace"  
Height="Auto" 
Width="Auto"
x:Name="busyControl">
<Grid Panel.ZIndex="10">
    <Border Opacity=".2">
        <Border.Background>
            <RadialGradientBrush>
                <GradientStop Color="#FF000000" Offset="0.59"/>
                <GradientStop Color="#FFB6B6B6" Offset="0"/>
            </RadialGradientBrush>
        </Border.Background>
    </Border>
    <Border VerticalAlignment="Center" 
                    HorizontalAlignment="Center"
                    BorderThickness="2"
                    BorderBrush="Gray">     
        <TextBlock Text="{Binding RelativeSource={RelativeSource FindAncestor,
                                                                 AncestorType=controls:BusyDialog},
                                                                 Path=BusyText}"
                   Opacity="1" 
                   Margin="20,10,20,10"/>
    </Border>
    <Grid.Style>
        <Style TargetType="Grid">
            <Setter Property="Visibility" Value="Hidden"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType=controls:BusyDialog},Path=IsBusy}" Value="True">
                    <Setter Property="Opacity" Value=".3" />
                    <Setter Property="IsEnabled" Value="False" />
                    <Setter Property="Visibility" Value="Visible"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Grid.Style>
</Grid>

and here is the code behind

public partial class BusyDialog : UserControl
{
    #region Dependency Properties

    public string BusyText
    {
        get { return (string)GetValue(BusyTextProperty); }
        set { SetValue(BusyTextProperty, value); }
    }

    public bool IsBusy
    {
        get{ return (bool)GetValue(IsBusyProperty); }
        set { SetValue(IsBusyProperty, value); }
    }

    public static readonly DependencyProperty IsBusyProperty =
        DependencyProperty.Register(
            "IsBusy", 
            typeof(bool), 
            typeof(BusyControl), 
            new FrameworkPropertyMetadata(
                false, 
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

    public static readonly DependencyProperty BusyTextProperty =
        DependencyProperty.Register(
            "BusyText", 
            typeof(string), 
            typeof(BusyControl), 
            new FrameworkPropertyMetadata(
                string.Empty, 
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
    #endregion

    public BusyDialog ()
    {
        InitializeComponent();
    }
}

Here's I'm creating the usercontrol in my view:

<localControls:BusyDialog x:Name="busyControl"
                               Grid.Row="0" 
                               IsBusy="{Binding IsWorking}"
                               BusyText="{Binding WorkingText}">
</localControls:BusyDialog>

Anything wrong with my code? Whenever I set the IsWorking property in my ViewModel, the control is not appearing as it's supposed to!

I also tried to set the user control binding like so:

<UserControl x:Class="MyNamespace.BusyDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:MyNamespace"  
Height="Auto" 
Width="Auto"
x:Name="busyControl">
<Grid Panel.ZIndex="10">
    <Border Opacity=".2">
        <Border.Background>
            <RadialGradientBrush>
                <GradientStop Color="#FF000000" Offset="0.59"/>
                <GradientStop Color="#FFB6B6B6" Offset="0"/>
            </RadialGradientBrush>
        </Border.Background>
    </Border>
    <Border VerticalAlignment="Center" 
                    HorizontalAlignment="Center"
                    BorderThickness="2"
                    BorderBrush="Gray">     
        <TextBlock Text="{Binding ElementName=busyControl, Path=BusyText}"
                   Opacity="1" 
                   Margin="20,10,20,10"/>
    </Border>
    <Grid.Style>
        <Style TargetType="Grid">
            <Setter Property="Visibility" Value="Hidden"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding ElementName=busyControl,Path=IsBusy}" Value="True">
                    <Setter Property="Opacity" Value=".3" />
                    <Setter Property="IsEnabled" Value="False" />
                    <Setter Property="Visibility" Value="Visible"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Grid.Style>
</Grid>

Upvotes: 1

Views: 1795

Answers (2)

Tri Q Tran
Tri Q Tran

Reputation: 5690

You need to implement INotifyPropertyChanged in your view model.

public class WorkingViewModel : INotifyPropertyChanged
{
    // ...

    private bool _isWorking;
    public bool IsWorking
    {
        get{ return _isWorking; }
        set {
                _isWorking = value;
                RaisePropertyChanged("IsWorking");
            }
    }

    // ...
    /// <summary>
    /// Occurs when a property value changes.
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;

    private void RaisePropertyChanged(string propertyName)
    {
        if(PopertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    // ...
}

This way, when your IsWorking changes, it will update the IsBusy in your BusyDialog control.

<localControls:BusyDialog x:Name="busyControl"
                               Grid.Row="0" 
                               IsBusy="{Binding IsWorking}"
                               BusyText="{Binding WorkingText}">
</localControls:BusyDialog>

Make sure to do the same for your WorkingText if you intend to change that too. Hope that helps.

Upvotes: 2

Pieter Breed
Pieter Breed

Reputation: 5689

The binding in the trigger seems weird to me. Try this:

<Trigger Property="IsBusy" Value="true">
    <Setter Property="Visibility" Value="Visible" />
    <Setter Property="Opacity" Value=".3" />
</Trigger>

When I'm reading your code the logic doesn't make complete sense to me. Is 0.3 Opacity enough for a control that must be visible? Remember to set up the default behavior via the Controls XAML and use the triggers to modify only the values appropriate to that state.

An example of what I'm trying to say is the IsEnabled setter on your trigger. This might very well be set in the main UserControl, since currently the control can only be Enabled when the control is hidden, when it's displayed it's disabled.

Does this make sense? Hope this helps!

Upvotes: 0

Related Questions